From b930725d71e86df8eb7924adafd2ac4a1b9924b2 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Tue, 19 Oct 2021 16:27:44 -0400 Subject: [PATCH] Collect additional vulnerability data, surface in JSON API (#10197) * Collect additional data from vulnerability reports * Surface vulnerabilities in JSON API * Address code review * Add help section * Update translations --- tests/common/db/integrations.py | 31 + .../vulnerabilities/test_package.py | 4 + tests/unit/legacy/api/test_json.py | 32 ++ .../integrations/vulnerabilities/__init__.py | 11 + .../integrations/vulnerabilities/models.py | 6 + .../integrations/vulnerabilities/utils.py | 2 + warehouse/legacy/api/json.py | 14 + warehouse/locale/messages.pot | 531 +++++++++--------- .../d582fb87b94c_add_details_and_fixed_in.py | 39 ++ warehouse/templates/pages/help.html | 16 + 10 files changed, 434 insertions(+), 252 deletions(-) create mode 100644 tests/common/db/integrations.py create mode 100644 warehouse/migrations/versions/d582fb87b94c_add_details_and_fixed_in.py diff --git a/tests/common/db/integrations.py b/tests/common/db/integrations.py new file mode 100644 index 000000000000..64744d383056 --- /dev/null +++ b/tests/common/db/integrations.py @@ -0,0 +1,31 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import factory + +from warehouse.integrations.vulnerabilities.models import VulnerabilityRecord + +from .base import WarehouseFactory +from .packaging import ReleaseFactory + + +class VulnerabilityRecordFactory(WarehouseFactory): + class Meta: + model = VulnerabilityRecord + + id = factory.fuzzy.FuzzyText(length=12) + source = factory.fuzzy.FuzzyText(length=12) + link = factory.fuzzy.FuzzyText(length=12) + aliases = factory.Sequence(lambda n: "alias" + str(n)) + releases = factory.SubFactory(ReleaseFactory) + details = factory.fuzzy.FuzzyText(length=12) + fixed_in = factory.Sequence(lambda n: str(n) + ".0") diff --git a/tests/unit/integration/vulnerabilities/test_package.py b/tests/unit/integration/vulnerabilities/test_package.py index 75d637bf072b..56521c2dbc0e 100644 --- a/tests/unit/integration/vulnerabilities/test_package.py +++ b/tests/unit/integration/vulnerabilities/test_package.py @@ -46,6 +46,8 @@ def test_vulnerability_report_request_from_api_request(): "id": "vuln_id", "link": "vulns.com/vuln_id", "aliases": ["vuln_alias"], + "details": "some details", + "events": [{"introduced": "1.0.0"}, {"fixed": "1.0.1"}, {"fixed": "2.0.0"}], } ) @@ -54,6 +56,8 @@ def test_vulnerability_report_request_from_api_request(): assert request.vulnerability_id == "vuln_id" assert request.advisory_link == "vulns.com/vuln_id" assert request.aliases == ["vuln_alias"] + assert request.details == "some details" + assert request.fixed_in == ["1.0.1", "2.0.0"] def test_invalid_vulnerability_report(): diff --git a/tests/unit/legacy/api/test_json.py b/tests/unit/legacy/api/test_json.py index a1066c1b1af1..6d6d70b86b46 100644 --- a/tests/unit/legacy/api/test_json.py +++ b/tests/unit/legacy/api/test_json.py @@ -20,6 +20,7 @@ from warehouse.packaging.models import Dependency, DependencyKind from ....common.db.accounts import UserFactory +from ....common.db.integrations import VulnerabilityRecordFactory from ....common.db.packaging import ( DescriptionFactory, FileFactory, @@ -432,6 +433,7 @@ def test_detail_renders(self, pyramid_config, db_request, db_session): } ], "last_serial": je.id, + "vulnerabilities": [], } def test_minimal_renders(self, pyramid_config, db_request): @@ -538,8 +540,38 @@ def test_minimal_renders(self, pyramid_config, db_request): } ], "last_serial": je.id, + "vulnerabilities": [], } + def test_vulnerabilities_renders(self, pyramid_config, db_request): + project = ProjectFactory.create(has_docs=False) + release = ReleaseFactory.create(project=project, version="0.1") + VulnerabilityRecordFactory.create( + id="PYSEC-001", + source="the source", + link="the link", + aliases=["alias1", "alias2"], + details="some details", + fixed_in=["3.3.2"], + releases=[release], + ) + + url = "/the/fake/url/" + db_request.route_url = pretend.call_recorder(lambda *args, **kw: url) + + result = json.json_release(release, db_request) + + assert result["vulnerabilities"] == [ + { + "id": "PYSEC-001", + "source": "the source", + "link": "the link", + "aliases": ["alias1", "alias2"], + "details": "some details", + "fixed_in": ["3.3.2"], + }, + ] + class TestJSONReleaseSlash: def test_normalizing_redirects(self, db_request): diff --git a/warehouse/integrations/vulnerabilities/__init__.py b/warehouse/integrations/vulnerabilities/__init__.py index ae8b2a672ae4..88a6ea72e8ea 100644 --- a/warehouse/integrations/vulnerabilities/__init__.py +++ b/warehouse/integrations/vulnerabilities/__init__.py @@ -30,12 +30,16 @@ def __init__( vulnerability_id: str, advisory_link: str, aliases: List[str], + details: str, + fixed_in: List[str], ): self.project = project self.versions = versions self.vulnerability_id = vulnerability_id self.advisory_link = advisory_link self.aliases = aliases + self.details = details + self.fixed_in = fixed_in @classmethod def from_api_request(cls, request): @@ -59,6 +63,13 @@ def from_api_request(cls, request): vulnerability_id=request["id"], advisory_link=request["link"], aliases=request["aliases"], + details=request.get("details"), + fixed_in=[ + version + for event in request.get("events", []) + for event_type, version in event.items() + if event_type == "fixed" + ], ) diff --git a/warehouse/integrations/vulnerabilities/models.py b/warehouse/integrations/vulnerabilities/models.py index 509cc9b84105..88bb0a99a8c6 100644 --- a/warehouse/integrations/vulnerabilities/models.py +++ b/warehouse/integrations/vulnerabilities/models.py @@ -58,6 +58,12 @@ class VulnerabilityRecord(db.Model): # e.g. "CVE-2021-12345" aliases = Column(ARRAY(String)) + # Details about the vulnerability + details = Column(String) + + # Events of introduced/fixed versions + fixed_in = Column(ARRAY(String)) + releases = orm.relationship( "Release", back_populates="vulnerabilities", diff --git a/warehouse/integrations/vulnerabilities/utils.py b/warehouse/integrations/vulnerabilities/utils.py index ea920ffb676a..851ebebfa2ea 100644 --- a/warehouse/integrations/vulnerabilities/utils.py +++ b/warehouse/integrations/vulnerabilities/utils.py @@ -89,6 +89,8 @@ def _analyze_vulnerability(request, vulnerability_report, origin, metrics): source=origin, link=report.advisory_link, aliases=report.aliases, + details=report.details, + fixed_in=report.fixed_in, ) _add_vuln_record(request, vulnerability_record) diff --git a/warehouse/legacy/api/json.py b/warehouse/legacy/api/json.py index 83b3532050e0..50b3da030c9f 100644 --- a/warehouse/legacy/api/json.py +++ b/warehouse/legacy/api/json.py @@ -163,6 +163,19 @@ def json_release(release, request): for r, fs in releases.items() } + # Serialize a list of vulnerabilties for this release + vulnerabilities = [ + { + "id": vulnerability_record.id, + "source": vulnerability_record.source, + "link": vulnerability_record.link, + "aliases": vulnerability_record.aliases, + "details": vulnerability_record.details, + "fixed_in": vulnerability_record.fixed_in, + } + for vulnerability_record in release.vulnerabilities + ] + return { "info": { "name": project.name, @@ -198,6 +211,7 @@ def json_release(release, request): }, "urls": releases[release.version], "releases": releases, + "vulnerabilities": vulnerabilities, "last_serial": project.last_serial, } diff --git a/warehouse/locale/messages.pot b/warehouse/locale/messages.pot index e1d3bd86f396..f68c74723545 100644 --- a/warehouse/locale/messages.pot +++ b/warehouse/locale/messages.pot @@ -315,65 +315,67 @@ msgstr "" #: warehouse/templates/packaging/detail.html:318 #: warehouse/templates/pages/classifiers.html:25 #: warehouse/templates/pages/help.html:20 -#: warehouse/templates/pages/help.html:204 -#: warehouse/templates/pages/help.html:211 -#: warehouse/templates/pages/help.html:225 -#: warehouse/templates/pages/help.html:241 -#: warehouse/templates/pages/help.html:245 -#: warehouse/templates/pages/help.html:302 -#: warehouse/templates/pages/help.html:329 -#: warehouse/templates/pages/help.html:334 -#: warehouse/templates/pages/help.html:339 -#: warehouse/templates/pages/help.html:341 -#: warehouse/templates/pages/help.html:346 -#: warehouse/templates/pages/help.html:347 -#: warehouse/templates/pages/help.html:348 -#: warehouse/templates/pages/help.html:352 -#: warehouse/templates/pages/help.html:385 -#: warehouse/templates/pages/help.html:387 +#: warehouse/templates/pages/help.html:207 +#: warehouse/templates/pages/help.html:214 +#: warehouse/templates/pages/help.html:228 +#: warehouse/templates/pages/help.html:244 +#: warehouse/templates/pages/help.html:248 +#: warehouse/templates/pages/help.html:305 +#: warehouse/templates/pages/help.html:332 +#: warehouse/templates/pages/help.html:337 +#: warehouse/templates/pages/help.html:342 +#: warehouse/templates/pages/help.html:344 +#: warehouse/templates/pages/help.html:349 +#: warehouse/templates/pages/help.html:350 +#: warehouse/templates/pages/help.html:351 +#: warehouse/templates/pages/help.html:355 +#: warehouse/templates/pages/help.html:388 #: warehouse/templates/pages/help.html:390 -#: warehouse/templates/pages/help.html:426 -#: warehouse/templates/pages/help.html:431 -#: warehouse/templates/pages/help.html:437 -#: warehouse/templates/pages/help.html:495 -#: warehouse/templates/pages/help.html:515 -#: warehouse/templates/pages/help.html:521 +#: warehouse/templates/pages/help.html:393 +#: warehouse/templates/pages/help.html:429 +#: warehouse/templates/pages/help.html:434 +#: warehouse/templates/pages/help.html:440 +#: warehouse/templates/pages/help.html:498 +#: warehouse/templates/pages/help.html:518 #: warehouse/templates/pages/help.html:524 -#: warehouse/templates/pages/help.html:526 -#: warehouse/templates/pages/help.html:535 -#: warehouse/templates/pages/help.html:547 -#: warehouse/templates/pages/help.html:553 -#: warehouse/templates/pages/help.html:565 -#: warehouse/templates/pages/help.html:566 -#: warehouse/templates/pages/help.html:571 -#: warehouse/templates/pages/help.html:596 -#: warehouse/templates/pages/help.html:627 -#: warehouse/templates/pages/help.html:650 -#: warehouse/templates/pages/help.html:657 -#: warehouse/templates/pages/help.html:669 -#: warehouse/templates/pages/help.html:680 +#: warehouse/templates/pages/help.html:527 +#: warehouse/templates/pages/help.html:529 +#: warehouse/templates/pages/help.html:538 +#: warehouse/templates/pages/help.html:550 +#: warehouse/templates/pages/help.html:556 +#: warehouse/templates/pages/help.html:568 +#: warehouse/templates/pages/help.html:569 +#: warehouse/templates/pages/help.html:574 +#: warehouse/templates/pages/help.html:599 +#: warehouse/templates/pages/help.html:612 +#: warehouse/templates/pages/help.html:617 +#: warehouse/templates/pages/help.html:643 +#: warehouse/templates/pages/help.html:666 +#: warehouse/templates/pages/help.html:673 #: warehouse/templates/pages/help.html:685 -#: warehouse/templates/pages/help.html:693 -#: warehouse/templates/pages/help.html:704 -#: warehouse/templates/pages/help.html:721 -#: warehouse/templates/pages/help.html:728 -#: warehouse/templates/pages/help.html:736 +#: warehouse/templates/pages/help.html:696 +#: warehouse/templates/pages/help.html:701 +#: warehouse/templates/pages/help.html:709 +#: warehouse/templates/pages/help.html:720 +#: warehouse/templates/pages/help.html:737 +#: warehouse/templates/pages/help.html:744 #: warehouse/templates/pages/help.html:752 -#: warehouse/templates/pages/help.html:757 -#: warehouse/templates/pages/help.html:762 -#: warehouse/templates/pages/help.html:772 -#: warehouse/templates/pages/help.html:781 -#: warehouse/templates/pages/help.html:795 -#: warehouse/templates/pages/help.html:803 +#: warehouse/templates/pages/help.html:768 +#: warehouse/templates/pages/help.html:773 +#: warehouse/templates/pages/help.html:778 +#: warehouse/templates/pages/help.html:788 +#: warehouse/templates/pages/help.html:797 #: warehouse/templates/pages/help.html:811 #: warehouse/templates/pages/help.html:819 -#: warehouse/templates/pages/help.html:829 -#: warehouse/templates/pages/help.html:844 -#: warehouse/templates/pages/help.html:859 +#: warehouse/templates/pages/help.html:827 +#: warehouse/templates/pages/help.html:835 +#: warehouse/templates/pages/help.html:845 #: warehouse/templates/pages/help.html:860 -#: warehouse/templates/pages/help.html:861 -#: warehouse/templates/pages/help.html:862 -#: warehouse/templates/pages/help.html:867 +#: warehouse/templates/pages/help.html:875 +#: warehouse/templates/pages/help.html:876 +#: warehouse/templates/pages/help.html:877 +#: warehouse/templates/pages/help.html:878 +#: warehouse/templates/pages/help.html:883 #: warehouse/templates/pages/security.html:36 #: warehouse/templates/pages/sponsors.html:33 #: warehouse/templates/pages/sponsors.html:37 @@ -458,7 +460,7 @@ msgstr "" #: warehouse/templates/base.html:41 warehouse/templates/base.html:55 #: warehouse/templates/base.html:265 #: warehouse/templates/includes/current-user-indicator.html:55 -#: warehouse/templates/pages/help.html:103 +#: warehouse/templates/pages/help.html:105 #: warehouse/templates/pages/sitemap.html:27 msgid "Help" msgstr "" @@ -1646,7 +1648,7 @@ msgstr "" #: warehouse/templates/includes/packaging/project-data.html:84 #: warehouse/templates/includes/packaging/project-data.html:86 -#: warehouse/templates/pages/help.html:557 +#: warehouse/templates/pages/help.html:560 msgid "Maintainer:" msgstr "" @@ -3006,7 +3008,7 @@ msgid "" msgstr "" #: warehouse/templates/manage/roles.html:39 -#: warehouse/templates/pages/help.html:556 +#: warehouse/templates/pages/help.html:559 msgid "There are two possible roles for collaborators:" msgstr "" @@ -3815,104 +3817,110 @@ msgid "" "project?" msgstr "" -#: warehouse/templates/pages/help.html:86 +#: warehouse/templates/pages/help.html:85 +msgid "" +"Where does PyPI get its data on project vulnerabilities from, and how can" +" I correct it?" +msgstr "" + +#: warehouse/templates/pages/help.html:88 msgid "" "Why am I getting a \"Filename or contents already exists\" or \"Filename " "has been previously used\" error?" msgstr "" -#: warehouse/templates/pages/help.html:87 +#: warehouse/templates/pages/help.html:89 msgid "Why isn't my desired project name available?" msgstr "" -#: warehouse/templates/pages/help.html:88 +#: warehouse/templates/pages/help.html:90 msgid "How do I claim an abandoned or previously registered project name?" msgstr "" -#: warehouse/templates/pages/help.html:89 +#: warehouse/templates/pages/help.html:91 msgid "What collaborator roles are available for a project on PyPI?" msgstr "" -#: warehouse/templates/pages/help.html:90 +#: warehouse/templates/pages/help.html:92 msgid "How do I become an owner/maintainer of a project on PyPI?" msgstr "" -#: warehouse/templates/pages/help.html:91 +#: warehouse/templates/pages/help.html:93 msgid "How can I upload a project description in a different format?" msgstr "" -#: warehouse/templates/pages/help.html:92 +#: warehouse/templates/pages/help.html:94 msgid "How do I request a new trove classifier?" msgstr "" -#: warehouse/templates/pages/help.html:93 +#: warehouse/templates/pages/help.html:95 msgid "Where can I report a bug or provide feedback about PyPI?" msgstr "" -#: warehouse/templates/pages/help.html:95 +#: warehouse/templates/pages/help.html:97 msgid "Who maintains PyPI?" msgstr "" -#: warehouse/templates/pages/help.html:96 +#: warehouse/templates/pages/help.html:98 msgid "What powers PyPI?" msgstr "" -#: warehouse/templates/pages/help.html:97 +#: warehouse/templates/pages/help.html:99 msgid "Can I depend on PyPI being available?" msgstr "" -#: warehouse/templates/pages/help.html:98 +#: warehouse/templates/pages/help.html:100 msgid "How can I contribute to PyPI?" msgstr "" -#: warehouse/templates/pages/help.html:99 +#: warehouse/templates/pages/help.html:101 msgid "How do I keep up with upcoming changes to PyPI?" msgstr "" -#: warehouse/templates/pages/help.html:100 +#: warehouse/templates/pages/help.html:102 msgid "" "What does the \"beta feature\" badge mean? What are Warehouse's current " "beta features?" msgstr "" -#: warehouse/templates/pages/help.html:101 +#: warehouse/templates/pages/help.html:103 msgid "How do I pronounce \"PyPI\"?" msgstr "" -#: warehouse/templates/pages/help.html:108 +#: warehouse/templates/pages/help.html:110 msgid "Common questions" msgstr "" -#: warehouse/templates/pages/help.html:111 -#: warehouse/templates/pages/help.html:192 +#: warehouse/templates/pages/help.html:113 +#: warehouse/templates/pages/help.html:195 msgid "Basics" msgstr "" -#: warehouse/templates/pages/help.html:122 +#: warehouse/templates/pages/help.html:124 msgid "My Account" msgstr "" -#: warehouse/templates/pages/help.html:139 -#: warehouse/templates/pages/help.html:512 +#: warehouse/templates/pages/help.html:141 +#: warehouse/templates/pages/help.html:515 msgid "Integrating" msgstr "" -#: warehouse/templates/pages/help.html:149 -#: warehouse/templates/pages/help.html:539 +#: warehouse/templates/pages/help.html:151 +#: warehouse/templates/pages/help.html:542 msgid "Administration of projects on PyPI" msgstr "" -#: warehouse/templates/pages/help.html:163 -#: warehouse/templates/pages/help.html:609 +#: warehouse/templates/pages/help.html:166 +#: warehouse/templates/pages/help.html:625 msgid "Troubleshooting" msgstr "" -#: warehouse/templates/pages/help.html:179 -#: warehouse/templates/pages/help.html:748 +#: warehouse/templates/pages/help.html:182 +#: warehouse/templates/pages/help.html:764 msgid "About" msgstr "" -#: warehouse/templates/pages/help.html:195 +#: warehouse/templates/pages/help.html:198 #, python-format msgid "" "\n" @@ -3936,7 +3944,7 @@ msgid "" " " msgstr "" -#: warehouse/templates/pages/help.html:204 +#: warehouse/templates/pages/help.html:207 #, python-format msgid "" "To learn how to install a file from PyPI, visit the Python Packaging User Guide." msgstr "" -#: warehouse/templates/pages/help.html:211 +#: warehouse/templates/pages/help.html:214 #, python-format msgid "" "For full instructions on configuring, packaging and distributing your " @@ -3956,7 +3964,7 @@ msgid "" "target=\"_blank\" rel=\"noopener\">Python Packaging User Guide." msgstr "" -#: warehouse/templates/pages/help.html:218 +#: warehouse/templates/pages/help.html:221 #, python-format msgid "" "Classifiers are used to categorize projects on PyPI. See PyPI itself has not suffered a breach. This is a protective measure " @@ -4044,7 +4052,7 @@ msgid "" "href=\"%(reset_pwd_href)s\">reset your password.

" msgstr "" -#: warehouse/templates/pages/help.html:280 +#: warehouse/templates/pages/help.html:283 #, python-format msgid "" "

All PyPI user events are stored under security history in account " @@ -4054,7 +4062,7 @@ msgid "" "href=\"mailto:%(admin_email)s\">%(admin_email)s

" msgstr "" -#: warehouse/templates/pages/help.html:292 +#: warehouse/templates/pages/help.html:295 msgid "" "

A PyPI API token linked to your account was posted on a public " "website. It was automatically revoked, but before regenerating a new one," @@ -4063,7 +4071,7 @@ msgid "" "applies too.

" msgstr "" -#: warehouse/templates/pages/help.html:302 +#: warehouse/templates/pages/help.html:305 #, python-format msgid "" "

Two factor authentication (2FA) makes your account more secure by " @@ -4082,7 +4090,7 @@ msgid "" "rel=\"noopener\">discuss.python.org.

" msgstr "" -#: warehouse/templates/pages/help.html:329 +#: warehouse/templates/pages/help.html:332 #, python-format msgid "" "PyPI users can set up two-factor authentication using any authentication " @@ -4091,21 +4099,21 @@ msgid "" "password\">TOTP standard." msgstr "" -#: warehouse/templates/pages/help.html:330 +#: warehouse/templates/pages/help.html:333 msgid "" "TOTP authentication " "applications generate a regularly changing authentication code to use " "when logging into your account." msgstr "" -#: warehouse/templates/pages/help.html:331 +#: warehouse/templates/pages/help.html:334 msgid "" "Because TOTP is an " "open standard, there are many applications that are compatible with your " "PyPI account. Popular applications include:" msgstr "" -#: warehouse/templates/pages/help.html:334 +#: warehouse/templates/pages/help.html:337 #, python-format msgid "" "Google Authenticator for iOS" msgstr "" -#: warehouse/templates/pages/help.html:337 -#: warehouse/templates/pages/help.html:339 -#: warehouse/templates/pages/help.html:344 -#: warehouse/templates/pages/help.html:346 +#: warehouse/templates/pages/help.html:340 +#: warehouse/templates/pages/help.html:342 +#: warehouse/templates/pages/help.html:347 +#: warehouse/templates/pages/help.html:349 msgid "(proprietary)" msgstr "" -#: warehouse/templates/pages/help.html:341 +#: warehouse/templates/pages/help.html:344 #, python-format msgid "" "Duo Mobile for iOS" msgstr "" -#: warehouse/templates/pages/help.html:347 -#: warehouse/templates/pages/help.html:348 +#: warehouse/templates/pages/help.html:350 +#: warehouse/templates/pages/help.html:351 msgid "(open source)" msgstr "" -#: warehouse/templates/pages/help.html:352 +#: warehouse/templates/pages/help.html:355 #, python-format msgid "" "Some password managers (e.g. 2FA with an " "authentication application:" msgstr "" -#: warehouse/templates/pages/help.html:362 +#: warehouse/templates/pages/help.html:365 msgid "" "Open an authentication (TOTP) application" msgstr "" -#: warehouse/templates/pages/help.html:363 +#: warehouse/templates/pages/help.html:366 msgid "" "Log in to your PyPI account, go to your account settings, and choose " "\"Add 2FA with " "authentication application\"" msgstr "" -#: warehouse/templates/pages/help.html:364 +#: warehouse/templates/pages/help.html:367 msgid "" "PyPI will generate a secret key, specific to your account. This is " "displayed as a QR code, and as a text code." msgstr "" -#: warehouse/templates/pages/help.html:365 +#: warehouse/templates/pages/help.html:368 msgid "" "Scan the QR code with your authentication application, or type it in " "manually. The method of input will depend on the application you have " "chosen." msgstr "" -#: warehouse/templates/pages/help.html:366 +#: warehouse/templates/pages/help.html:369 msgid "" "Your application will generate an authentication code - use this to " "verify your set up on PyPI" msgstr "" -#: warehouse/templates/pages/help.html:369 +#: warehouse/templates/pages/help.html:372 msgid "" "The PyPI server and your application now share your PyPI secret key, " "allowing your application to generate valid authentication codes for your" " PyPI account." msgstr "" -#: warehouse/templates/pages/help.html:371 -#: warehouse/templates/pages/help.html:413 +#: warehouse/templates/pages/help.html:374 +#: warehouse/templates/pages/help.html:416 msgid "Next time you log in to PyPI you'll need to:" msgstr "" -#: warehouse/templates/pages/help.html:373 -#: warehouse/templates/pages/help.html:465 +#: warehouse/templates/pages/help.html:376 +#: warehouse/templates/pages/help.html:468 msgid "Provide your username and password, as normal" msgstr "" -#: warehouse/templates/pages/help.html:374 +#: warehouse/templates/pages/help.html:377 msgid "Open your authentication application to generate an authentication code" msgstr "" -#: warehouse/templates/pages/help.html:375 +#: warehouse/templates/pages/help.html:378 msgid "Use this code to finish logging into PyPI" msgstr "" -#: warehouse/templates/pages/help.html:381 +#: warehouse/templates/pages/help.html:384 msgid "" "A security device is a USB key or other " "device that generates a one-time password and sends that password to " @@ -4215,11 +4223,11 @@ msgid "" "user." msgstr "" -#: warehouse/templates/pages/help.html:383 +#: warehouse/templates/pages/help.html:386 msgid "To set up two factor authentication with a USB key, you'll need:" msgstr "" -#: warehouse/templates/pages/help.html:385 +#: warehouse/templates/pages/help.html:388 #, python-format msgid "" "To use a :" msgstr "" -#: warehouse/templates/pages/help.html:390 +#: warehouse/templates/pages/help.html:393 #, python-format msgid "" "Popular keys include Thetis." msgstr "" -#: warehouse/templates/pages/help.html:397 +#: warehouse/templates/pages/help.html:400 msgid "" "Note that some older Yubico USB keys do not follow the FIDO " "specification, and will therefore not work with PyPI" msgstr "" -#: warehouse/templates/pages/help.html:402 +#: warehouse/templates/pages/help.html:405 msgid "Follow these steps:" msgstr "" -#: warehouse/templates/pages/help.html:404 +#: warehouse/templates/pages/help.html:407 msgid "" "\n" "
  • Log in to your PyPI account, go to your account settings, " @@ -4274,13 +4282,13 @@ msgid "" " " msgstr "" -#: warehouse/templates/pages/help.html:411 +#: warehouse/templates/pages/help.html:414 msgid "" "Once complete, your USB key will be registered to your PyPI account and " "can be used during the log in process." msgstr "" -#: warehouse/templates/pages/help.html:415 +#: warehouse/templates/pages/help.html:418 msgid "" "\n" "
  • Provide your username and password, as normal
  • \n" @@ -4289,7 +4297,7 @@ msgid "" " " msgstr "" -#: warehouse/templates/pages/help.html:426 +#: warehouse/templates/pages/help.html:429 #, python-format msgid "" "There is a growing ecosystem of mobile phones to act as security devices." msgstr "" -#: warehouse/templates/pages/help.html:437 +#: warehouse/templates/pages/help.html:440 #, python-format msgid "" "As PyPI's two factor implementation follows the authentication " "application or security device, you can use " "these codes to sign into PyPI." msgstr "" -#: warehouse/templates/pages/help.html:449 +#: warehouse/templates/pages/help.html:452 msgid "" "Recovery codes are one time use. They are not a " "substitute for a authentication application or API tokens provide an alternative way (instead of username " @@ -4391,41 +4399,41 @@ msgid "" " " msgstr "" -#: warehouse/templates/pages/help.html:480 +#: warehouse/templates/pages/help.html:483 msgid "To make an API token:" msgstr "" -#: warehouse/templates/pages/help.html:483 +#: warehouse/templates/pages/help.html:486 msgid "Verify your email address" msgstr "" -#: warehouse/templates/pages/help.html:483 +#: warehouse/templates/pages/help.html:486 #, python-format msgid "(check your account settings)" msgstr "" -#: warehouse/templates/pages/help.html:484 +#: warehouse/templates/pages/help.html:487 #, python-format msgid "" "In your account settings, go to the API tokens " "section and select \"Add API token\"" msgstr "" -#: warehouse/templates/pages/help.html:487 +#: warehouse/templates/pages/help.html:490 msgid "To use an API token:" msgstr "" -#: warehouse/templates/pages/help.html:490 +#: warehouse/templates/pages/help.html:493 msgid "Set your username to __token__" msgstr "" -#: warehouse/templates/pages/help.html:491 +#: warehouse/templates/pages/help.html:494 msgid "" "Set your password to the token value, including the pypi- " "prefix" msgstr "" -#: warehouse/templates/pages/help.html:495 +#: warehouse/templates/pages/help.html:498 #, python-format msgid "" "Where you edit or add these values will depend on your individual use " @@ -4437,14 +4445,14 @@ msgid "" "rel=\"noopener\">.travis.yml if you are using Travis)." msgstr "" -#: warehouse/templates/pages/help.html:499 +#: warehouse/templates/pages/help.html:502 msgid "" "Advanced users may wish to inspect their token by decoding it with " "base64, and checking the output against the unique identifier displayed " "on PyPI." msgstr "" -#: warehouse/templates/pages/help.html:503 +#: warehouse/templates/pages/help.html:506 msgid "" "\n" "

    PyPI asks you to confirm your password before you want to " @@ -4458,15 +4466,15 @@ msgid "" " " msgstr "" -#: warehouse/templates/pages/help.html:515 +#: warehouse/templates/pages/help.html:518 msgid "Yes, including RSS feeds of new packages and new releases." msgstr "" -#: warehouse/templates/pages/help.html:515 +#: warehouse/templates/pages/help.html:518 msgid "See the API reference." msgstr "" -#: warehouse/templates/pages/help.html:518 +#: warehouse/templates/pages/help.html:521 #, python-format msgid "" "If you need to run your own mirror of PyPI, the GitHub apps." msgstr "" -#: warehouse/templates/pages/help.html:524 +#: warehouse/templates/pages/help.html:527 #, python-format msgid "" "You can analyze PyPI project/package metadata and via our public dataset on Google BigQuery." msgstr "" -#: warehouse/templates/pages/help.html:526 +#: warehouse/templates/pages/help.html:529 #, python-format msgid "" "other relevant factors." msgstr "" -#: warehouse/templates/pages/help.html:535 +#: warehouse/templates/pages/help.html:538 #, python-format msgid "" "For recent statistics on uptime and performance, see ." msgstr "" -#: warehouse/templates/pages/help.html:542 +#: warehouse/templates/pages/help.html:545 #, python-format msgid "" "PyPI does not support publishing private packages. If you need to publish" @@ -4525,7 +4533,7 @@ msgid "" "run your own deployment of the devpi project." msgstr "" -#: warehouse/templates/pages/help.html:545 +#: warehouse/templates/pages/help.html:548 msgid "" "Your publishing tool may return an error that your new project can't be " "created with your desired name, despite no evidence of a project or " @@ -4533,7 +4541,7 @@ msgid "" "reasons this may occur:" msgstr "" -#: warehouse/templates/pages/help.html:547 +#: warehouse/templates/pages/help.html:550 #, python-format msgid "" "The project name conflicts with a module from any major version from 2.5 to present." msgstr "" -#: warehouse/templates/pages/help.html:548 +#: warehouse/templates/pages/help.html:551 #, python-format msgid "" "The project name has been explicitly prohibited by the PyPI " @@ -4550,13 +4558,13 @@ msgid "" "with a malicious package." msgstr "" -#: warehouse/templates/pages/help.html:549 +#: warehouse/templates/pages/help.html:552 msgid "" "The project name has been registered by another user, but no releases " "have been created." msgstr "" -#: warehouse/templates/pages/help.html:553 +#: warehouse/templates/pages/help.html:556 #, python-format msgid "" "Follow the PEP 541." msgstr "" -#: warehouse/templates/pages/help.html:557 +#: warehouse/templates/pages/help.html:560 msgid "" "Can upload releases for a package. Cannot add collaborators. Cannot " "delete files, releases, or the project." msgstr "" -#: warehouse/templates/pages/help.html:558 +#: warehouse/templates/pages/help.html:561 msgid "Owner:" msgstr "" -#: warehouse/templates/pages/help.html:558 +#: warehouse/templates/pages/help.html:561 msgid "" "Can upload releases. Can add other collaborators. Can delete files, " "releases, or the entire project." msgstr "" -#: warehouse/templates/pages/help.html:561 +#: warehouse/templates/pages/help.html:564 msgid "" "Only the current owners of a project have the ability to add new owners " "or maintainers. If you need to request ownership, you should contact the " @@ -4589,12 +4597,12 @@ msgid "" "project page." msgstr "" -#: warehouse/templates/pages/help.html:562 +#: warehouse/templates/pages/help.html:565 #, python-format msgid "If the owner is unresponsive, see %(anchor_text)s" msgstr "" -#: warehouse/templates/pages/help.html:565 +#: warehouse/templates/pages/help.html:568 #, python-format msgid "" "By default, an upload's description will render with file an issue and tell us:" msgstr "" -#: warehouse/templates/pages/help.html:580 -#: warehouse/templates/pages/help.html:601 +#: warehouse/templates/pages/help.html:583 +#: warehouse/templates/pages/help.html:604 msgid "A link to your project on PyPI (or Test PyPI)" msgstr "" -#: warehouse/templates/pages/help.html:581 +#: warehouse/templates/pages/help.html:584 msgid "The size of your release, in megabytes" msgstr "" -#: warehouse/templates/pages/help.html:582 +#: warehouse/templates/pages/help.html:585 msgid "Which index/indexes you need the increase for (PyPI, Test PyPI, or both)" msgstr "" -#: warehouse/templates/pages/help.html:583 -#: warehouse/templates/pages/help.html:603 +#: warehouse/templates/pages/help.html:586 +#: warehouse/templates/pages/help.html:606 msgid "" "A brief description of your project, including the reason for the " "additional size." msgstr "" -#: warehouse/templates/pages/help.html:589 +#: warehouse/templates/pages/help.html:592 msgid "" "If you can't upload your project's release to PyPI because you're hitting" " the project size limit, first remove any unnecessary releases or " "individual files to lower your overall project size." msgstr "" -#: warehouse/templates/pages/help.html:596 +#: warehouse/templates/pages/help.html:599 #, python-format msgid "" "If that is not possible, we can sometimes increase your limit. File an issue and tell us:" msgstr "" -#: warehouse/templates/pages/help.html:602 +#: warehouse/templates/pages/help.html:605 msgid "The total size of your project, in gigabytes" msgstr "" #: warehouse/templates/pages/help.html:612 +#, python-format +msgid "" +"PyPI receives reports on vulnerabilities in the packages hosted on it " +"from the Open Source Vulnerabilities project, which in turn " +"ingests vulnerabilities from the Python Packaging " +"Advisory Database." +msgstr "" + +#: warehouse/templates/pages/help.html:617 +#, python-format +msgid "" +"If you believe vulnerability data for your project is invalid or " +"incorrect, file an issue with details." +msgstr "" + +#: warehouse/templates/pages/help.html:628 msgid "" "If you've forgotten your PyPI password but you remember your email " "address or username, follow these steps to reset your password:" msgstr "" -#: warehouse/templates/pages/help.html:614 +#: warehouse/templates/pages/help.html:630 #, python-format msgid "Go to reset your password." msgstr "" -#: warehouse/templates/pages/help.html:615 +#: warehouse/templates/pages/help.html:631 msgid "Enter the email address or username you used for PyPI and submit the form." msgstr "" -#: warehouse/templates/pages/help.html:616 +#: warehouse/templates/pages/help.html:632 msgid "You'll receive an email with a password reset link." msgstr "" -#: warehouse/templates/pages/help.html:621 +#: warehouse/templates/pages/help.html:637 msgid "If you've lost access to your PyPI account due to:" msgstr "" -#: warehouse/templates/pages/help.html:623 +#: warehouse/templates/pages/help.html:639 msgid "Lost access to the email address associated with your account" msgstr "" -#: warehouse/templates/pages/help.html:624 +#: warehouse/templates/pages/help.html:640 msgid "" "Lost two factor authentication application, device, and recovery " "codes" msgstr "" -#: warehouse/templates/pages/help.html:627 +#: warehouse/templates/pages/help.html:643 #, python-format msgid "" "You can proceed to API Token for uploads:" msgstr "" -#: warehouse/templates/pages/help.html:641 +#: warehouse/templates/pages/help.html:657 msgid "Ensure that your API Token is valid and has not been revoked." msgstr "" -#: warehouse/templates/pages/help.html:642 +#: warehouse/templates/pages/help.html:658 msgid "" "Ensure that your API Token is properly " "formatted and does not contain any trailing characters such as " "newlines." msgstr "" -#: warehouse/templates/pages/help.html:644 +#: warehouse/templates/pages/help.html:660 msgid "" "In both cases, remember that PyPI and TestPyPI each require you to create" " an account, so your credentials may be different." msgstr "" -#: warehouse/templates/pages/help.html:646 +#: warehouse/templates/pages/help.html:662 msgid "" "\n" " If you're using Windows and trying to paste your password or " @@ -4762,7 +4789,7 @@ msgid "" " " msgstr "" -#: warehouse/templates/pages/help.html:650 +#: warehouse/templates/pages/help.html:666 #, python-format msgid "" "This is a Learn why on the PSF blog." msgstr "" -#: warehouse/templates/pages/help.html:664 +#: warehouse/templates/pages/help.html:680 #, python-format msgid "" "If you are having trouble with %(command)s and get a " @@ -4791,7 +4818,7 @@ msgid "" "information:" msgstr "" -#: warehouse/templates/pages/help.html:666 +#: warehouse/templates/pages/help.html:682 msgid "" "If you see an error like There was a problem confirming the ssl " "certificate or tlsv1 alert protocol version or " @@ -4799,7 +4826,7 @@ msgid "" "PyPI with a newer TLS support library." msgstr "" -#: warehouse/templates/pages/help.html:667 +#: warehouse/templates/pages/help.html:683 msgid "" "The specific steps you need to take will depend on your operating system " "version, where your installation of Python originated (python.org, your " @@ -4807,7 +4834,7 @@ msgid "" " Python, setuptools, and pip." msgstr "" -#: warehouse/templates/pages/help.html:669 +#: warehouse/templates/pages/help.html:685 #, python-format msgid "" "For help, go to %(command)s." msgstr "" -#: warehouse/templates/pages/help.html:680 +#: warehouse/templates/pages/help.html:696 #, python-format msgid "" "We take , so we can try to fix the problem, for you and others." msgstr "" -#: warehouse/templates/pages/help.html:693 +#: warehouse/templates/pages/help.html:709 #, python-format msgid "" "In a previous version of PyPI, it used to be possible for maintainers to " @@ -4846,7 +4873,7 @@ msgid "" "rel=\"noopener\">use twine to upload your project to PyPI." msgstr "" -#: warehouse/templates/pages/help.html:702 +#: warehouse/templates/pages/help.html:718 msgid "" "Spammers return to PyPI with some regularity hoping to place their Search" " Engine Optimized phishing, scam, and click-farming content on the site. " @@ -4855,7 +4882,7 @@ msgid "" "prime target." msgstr "" -#: warehouse/templates/pages/help.html:704 +#: warehouse/templates/pages/help.html:720 #, python-format msgid "" "When the PyPI administrators are overwhelmed by spam or " @@ -4866,29 +4893,29 @@ msgid "" "have updated it with reasoning for the intervention." msgstr "" -#: warehouse/templates/pages/help.html:713 +#: warehouse/templates/pages/help.html:729 msgid "PyPI will return these errors for one of these reasons:" msgstr "" -#: warehouse/templates/pages/help.html:715 +#: warehouse/templates/pages/help.html:731 msgid "Filename has been used and file exists" msgstr "" -#: warehouse/templates/pages/help.html:716 +#: warehouse/templates/pages/help.html:732 msgid "Filename has been used but file no longer exists" msgstr "" -#: warehouse/templates/pages/help.html:717 +#: warehouse/templates/pages/help.html:733 msgid "A file with the exact same content exists" msgstr "" -#: warehouse/templates/pages/help.html:719 +#: warehouse/templates/pages/help.html:735 msgid "" "PyPI does not allow for a filename to be reused, even once a project has " "been deleted and recreated." msgstr "" -#: warehouse/templates/pages/help.html:721 +#: warehouse/templates/pages/help.html:737 #, python-format msgid "" "To avoid this situation, pypi.org." msgstr "" -#: warehouse/templates/pages/help.html:728 +#: warehouse/templates/pages/help.html:744 #, python-format msgid "" "If you would like to request a new trove classifier file a pull request " @@ -4906,7 +4933,7 @@ msgid "" " to include a brief justification of why it is important." msgstr "" -#: warehouse/templates/pages/help.html:736 +#: warehouse/templates/pages/help.html:752 #, python-format msgid "" "If you're experiencing an issue with PyPI itself, we welcome " @@ -4917,14 +4944,14 @@ msgid "" " first check that a similar issue does not already exist." msgstr "" -#: warehouse/templates/pages/help.html:743 +#: warehouse/templates/pages/help.html:759 msgid "" "If you are having an issue is with a specific package installed from " "PyPI, you should reach out to the maintainers of that project directly " "instead." msgstr "" -#: warehouse/templates/pages/help.html:752 +#: warehouse/templates/pages/help.html:768 #, python-format msgid "" "PyPI is powered by the Warehouse project; ." msgstr "" -#: warehouse/templates/pages/help.html:779 +#: warehouse/templates/pages/help.html:795 msgid "" "As of April 16, 2018, PyPI.org is at \"production\" status, meaning that " "it has moved out of beta and replaced the old site (pypi.python.org). It " "is now robust, tested, and ready for expected browser and API traffic." msgstr "" -#: warehouse/templates/pages/help.html:781 +#: warehouse/templates/pages/help.html:797 #, python-format msgid "" "PyPI is heavily cached and distributed via private index." msgstr "" -#: warehouse/templates/pages/help.html:795 +#: warehouse/templates/pages/help.html:811 #, python-format msgid "" "We have a huge amount of work to do to continue to maintain and improve " @@ -4997,22 +5024,22 @@ msgid "" "target=\"_blank\" rel=\"noopener\">the Warehouse project)." msgstr "" -#: warehouse/templates/pages/help.html:800 +#: warehouse/templates/pages/help.html:816 msgid "Financial:" msgstr "" -#: warehouse/templates/pages/help.html:800 +#: warehouse/templates/pages/help.html:816 #, python-format msgid "" "We would deeply appreciate your donations to fund " "development and maintenance." msgstr "" -#: warehouse/templates/pages/help.html:801 +#: warehouse/templates/pages/help.html:817 msgid "Development:" msgstr "" -#: warehouse/templates/pages/help.html:801 +#: warehouse/templates/pages/help.html:817 msgid "" "Warehouse is open source, and we would love to see some new faces working" " on the project. You do not need to be an experienced " @@ -5020,7 +5047,7 @@ msgid "" " you make your first open source pull request!" msgstr "" -#: warehouse/templates/pages/help.html:803 +#: warehouse/templates/pages/help.html:819 #, python-format msgid "" "If you have skills in Python, ElasticSearch, HTML, SCSS, JavaScript, or " @@ -5034,7 +5061,7 @@ msgid "" "here." msgstr "" -#: warehouse/templates/pages/help.html:811 +#: warehouse/templates/pages/help.html:827 #, python-format msgid "" "Issues are grouped into Python packaging forum on Discourse." msgstr "" -#: warehouse/templates/pages/help.html:829 +#: warehouse/templates/pages/help.html:845 #, python-format msgid "" "Changes to PyPI are generally announced on both the {% trans %}Administration of projects on PyPI{% en

  • {{ description_content_type() }}
  • {{ file_size_limit() }}
  • {{ project_size_limit() }}
  • +
  • {{ vulnerability-data() }}
  • @@ -603,6 +606,19 @@

    {{ project_size_limit() }}

  • {% trans %}A brief description of your project, including the reason for the additional size.{% endtrans %}
  • {{ code_of_conduct() }} + +

    {{ vulnerability_data() }}

    +

    + {% trans trimmed osv_href='https://osv.dev/', title=gettext('External link'), vulns_href='https://github.com/pypa/advisory-db' %} + PyPI receives reports on vulnerabilities in the packages hosted on it from the Open Source Vulnerabilities project, which in turn ingests vulnerabilities from the Python Packaging Advisory Database. + {% endtrans %} +

    +

    + {% trans trimmed file_issue_href='https://github.com/pypa/advisory-db/issues', title=gettext('External link') %} + If you believe vulnerability data for your project is invalid or incorrect, file an issue with details. + {% endtrans %} +

    +