We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Vulnerability reporting task is not resilient to deleted releases
Currently attempting to publish a vulnerability report for a notification that includes release versions that have been deleted (or never existed) causes an error and prevents the entire report from being stored.

Example: https://sentry.io/share/issue/69362937025d4524be01918a80f830d1/

If the release is not found, we should just skip that version and continue storing the vulnerability report. If *none* of the versions are found, we should error.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `warehouse/integrations/vulnerabilities/utils.py`
Content:
```
1 # Licensed under the Apache License, Version 2.0 (the "License");
2 # you may not use this file except in compliance with the License.
3 # You may obtain a copy of the License at
4 #
5 # http://www.apache.org/licenses/LICENSE-2.0
6 #
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS,
9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 # See the License for the specific language governing permissions and
11 # limitations under the License.
12 
13 
14 from sqlalchemy import func, orm
15 from sqlalchemy.orm.exc import NoResultFound
16 
17 from warehouse.integrations import vulnerabilities
18 from warehouse.integrations.vulnerabilities.models import VulnerabilityRecord
19 from warehouse.packaging.models import Project, Release
20 
21 
22 def _get_project(request, vuln_report: vulnerabilities.VulnerabilityReportRequest):
23     return (
24         request.db.query(Project)
25         .filter(
26             Project.normalized_name == func.normalize_pep426_name(vuln_report.project)
27         )
28         .one()
29     )
30 
31 
32 def _get_release(request, project: Project, version):
33     return (
34         request.db.query(Release)
35         .filter(Release.project_id == project.id)
36         .filter(Release.version == version)
37         .one()
38     )
39 
40 
41 def _get_vuln_record(
42     request, vuln_report: vulnerabilities.VulnerabilityReportRequest, origin
43 ):
44     return (
45         request.db.query(VulnerabilityRecord)
46         .filter(VulnerabilityRecord.id == vuln_report.vulnerability_id)
47         .filter(VulnerabilityRecord.source == origin)
48         .options(orm.joinedload(VulnerabilityRecord.releases))
49         .one()
50     )
51 
52 
53 def _delete_vuln_record(request, vuln_record: VulnerabilityRecord):
54     request.db.delete(vuln_record)
55 
56 
57 def _add_vuln_record(request, vuln_record: VulnerabilityRecord):
58     request.db.add(vuln_record)
59 
60 
61 def _analyze_vulnerability(request, vulnerability_report, origin, metrics):
62     try:
63         report = vulnerabilities.VulnerabilityReportRequest.from_api_request(
64             request=vulnerability_report
65         )
66     except vulnerabilities.InvalidVulnerabilityReportRequest as exc:
67         metrics.increment(
68             f"warehouse.vulnerabilities.error.{exc.reason}", tags=[f"origin:{origin}"]
69         )
70         raise
71 
72     metrics.increment("warehouse.vulnerabilities.valid", tags=[f"origin:{origin}"])
73 
74     try:
75         vulnerability_record = _get_vuln_record(request, report, origin)
76 
77         if not report.versions:
78             # No versions indicates the vulnerability is no longer considered
79             # valid, so delete it.
80             _delete_vuln_record(request, vulnerability_record)
81             return
82 
83     except NoResultFound:
84         if not report.versions:
85             return
86 
87         vulnerability_record = VulnerabilityRecord(
88             id=report.vulnerability_id,
89             source=origin,
90             link=report.advisory_link,
91             aliases=report.aliases,
92         )
93         _add_vuln_record(request, vulnerability_record)
94 
95     try:
96         project = _get_project(request, report)
97     except NoResultFound:
98         metrics.increment(
99             "warehouse.vulnerabilities.error.project_not_found",
100             tags=[f"origin:{origin}"],
101         )
102         raise
103 
104     for version in report.versions:
105         try:
106             release = _get_release(request, project, version)
107         except NoResultFound:
108             metrics.increment(
109                 "warehouse.vulnerabilities.error.release_not_found",
110                 tags=[f"origin:{origin}"],
111             )
112             raise
113 
114         if release not in vulnerability_record.releases:
115             vulnerability_record.releases.append(release)
116 
117     # Unassociate any releases that no longer apply.
118     for release in list(vulnerability_record.releases):
119         if release.version not in report.versions:
120             vulnerability_record.releases.remove(release)
121 
122 
123 def analyze_vulnerability(request, vulnerability_report, origin, metrics):
124     metrics.increment("warehouse.vulnerabilities.received", tags=[f"origin:{origin}"])
125     try:
126         with metrics.timed(
127             "warehouse.vulnerabilities.analysis", tags=[f"origin:{origin}"]
128         ):
129             _analyze_vulnerability(
130                 request=request,
131                 vulnerability_report=vulnerability_report,
132                 origin=origin,
133                 metrics=metrics,
134             )
135 
136         metrics.increment(
137             "warehouse.vulnerabilities.processed", tags=[f"origin:{origin}"]
138         )
139     except (vulnerabilities.InvalidVulnerabilityReportRequest, NoResultFound):
140         raise
141     except Exception:
142         metrics.increment(
143             "warehouse.vulnerabilities.error.unknown", tags=[f"origin:{origin}"]
144         )
145         raise
146 
147 
148 def analyze_vulnerabilities(request, vulnerability_reports, origin, metrics):
149     from warehouse.integrations.vulnerabilities import tasks
150 
151     if not isinstance(vulnerability_reports, list):
152         metrics.increment(
153             "warehouse.vulnerabilities.error.format", tags=[f"origin:{origin}"]
154         )
155         raise vulnerabilities.InvalidVulnerabilityReportRequest(
156             "Invalid format: payload is not a list", "format"
157         )
158 
159     for vulnerability_report in vulnerability_reports:
160         request.task(tasks.analyze_vulnerability_task).delay(
161             vulnerability_report=vulnerability_report,
162             origin=origin,
163         )
164
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/warehouse/integrations/vulnerabilities/utils.py b/warehouse/integrations/vulnerabilities/utils.py
--- a/warehouse/integrations/vulnerabilities/utils.py
+++ b/warehouse/integrations/vulnerabilities/utils.py
@@ -10,7 +10,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
+from pyramid.httpexceptions import HTTPBadRequest
 from sqlalchemy import func, orm
 from sqlalchemy.orm.exc import NoResultFound
 
@@ -101,19 +101,26 @@
         )
         raise
 
+    found_releases = False  # by now, we don't have any release found
+
     for version in report.versions:
         try:
             release = _get_release(request, project, version)
+            found_releases = True  # at least one release found
         except NoResultFound:
             metrics.increment(
                 "warehouse.vulnerabilities.error.release_not_found",
                 tags=[f"origin:{origin}"],
             )
-            raise
+            continue  # skip that release
 
         if release not in vulnerability_record.releases:
             vulnerability_record.releases.append(release)
 
+    if not found_releases:
+        # no releases found, then raise an exception
+        raise HTTPBadRequest("None of the releases were found")
+
     # Unassociate any releases that no longer apply.
     for release in list(vulnerability_record.releases):
         if release.version not in report.versions:
@@ -136,7 +143,11 @@
         metrics.increment(
             "warehouse.vulnerabilities.processed", tags=[f"origin:{origin}"]
         )
-    except (vulnerabilities.InvalidVulnerabilityReportRequest, NoResultFound):
+    except (
+        vulnerabilities.InvalidVulnerabilityReportRequest,
+        NoResultFound,
+        HTTPBadRequest,
+    ):
         raise
     except Exception:
         metrics.increment(

{"golden_diff": "diff --git a/warehouse/integrations/vulnerabilities/utils.py b/warehouse/integrations/vulnerabilities/utils.py\n--- a/warehouse/integrations/vulnerabilities/utils.py\n+++ b/warehouse/integrations/vulnerabilities/utils.py\n@@ -10,7 +10,7 @@\n # See the License for the specific language governing permissions and\n # limitations under the License.\n \n-\n+from pyramid.httpexceptions import HTTPBadRequest\n from sqlalchemy import func, orm\n from sqlalchemy.orm.exc import NoResultFound\n \n@@ -101,19 +101,26 @@\n         )\n         raise\n \n+    found_releases = False  # by now, we don't have any release found\n+\n     for version in report.versions:\n         try:\n             release = _get_release(request, project, version)\n+            found_releases = True  # at least one release found\n         except NoResultFound:\n             metrics.increment(\n                 \"warehouse.vulnerabilities.error.release_not_found\",\n                 tags=[f\"origin:{origin}\"],\n             )\n-            raise\n+            continue  # skip that release\n \n         if release not in vulnerability_record.releases:\n             vulnerability_record.releases.append(release)\n \n+    if not found_releases:\n+        # no releases found, then raise an exception\n+        raise HTTPBadRequest(\"None of the releases were found\")\n+\n     # Unassociate any releases that no longer apply.\n     for release in list(vulnerability_record.releases):\n         if release.version not in report.versions:\n@@ -136,7 +143,11 @@\n         metrics.increment(\n             \"warehouse.vulnerabilities.processed\", tags=[f\"origin:{origin}\"]\n         )\n-    except (vulnerabilities.InvalidVulnerabilityReportRequest, NoResultFound):\n+    except (\n+        vulnerabilities.InvalidVulnerabilityReportRequest,\n+        NoResultFound,\n+        HTTPBadRequest,\n+    ):\n         raise\n     except Exception:\n         metrics.increment(\n", "issue": "Vulnerability reporting task is not resilient to deleted releases\nCurrently attempting to publish a vulnerability report for a notification that includes release versions that have been deleted (or never existed) causes an error and prevents the entire report from being stored.\r\n\r\nExample: https://sentry.io/share/issue/69362937025d4524be01918a80f830d1/\r\n\r\nIf the release is not found, we should just skip that version and continue storing the vulnerability report. If *none* of the versions are found, we should error.\n", "before_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\nfrom sqlalchemy import func, orm\nfrom sqlalchemy.orm.exc import NoResultFound\n\nfrom warehouse.integrations import vulnerabilities\nfrom warehouse.integrations.vulnerabilities.models import VulnerabilityRecord\nfrom warehouse.packaging.models import Project, Release\n\n\ndef _get_project(request, vuln_report: vulnerabilities.VulnerabilityReportRequest):\n    return (\n        request.db.query(Project)\n        .filter(\n            Project.normalized_name == func.normalize_pep426_name(vuln_report.project)\n        )\n        .one()\n    )\n\n\ndef _get_release(request, project: Project, version):\n    return (\n        request.db.query(Release)\n        .filter(Release.project_id == project.id)\n        .filter(Release.version == version)\n        .one()\n    )\n\n\ndef _get_vuln_record(\n    request, vuln_report: vulnerabilities.VulnerabilityReportRequest, origin\n):\n    return (\n        request.db.query(VulnerabilityRecord)\n        .filter(VulnerabilityRecord.id == vuln_report.vulnerability_id)\n        .filter(VulnerabilityRecord.source == origin)\n        .options(orm.joinedload(VulnerabilityRecord.releases))\n        .one()\n    )\n\n\ndef _delete_vuln_record(request, vuln_record: VulnerabilityRecord):\n    request.db.delete(vuln_record)\n\n\ndef _add_vuln_record(request, vuln_record: VulnerabilityRecord):\n    request.db.add(vuln_record)\n\n\ndef _analyze_vulnerability(request, vulnerability_report, origin, metrics):\n    try:\n        report = vulnerabilities.VulnerabilityReportRequest.from_api_request(\n            request=vulnerability_report\n        )\n    except vulnerabilities.InvalidVulnerabilityReportRequest as exc:\n        metrics.increment(\n            f\"warehouse.vulnerabilities.error.{exc.reason}\", tags=[f\"origin:{origin}\"]\n        )\n        raise\n\n    metrics.increment(\"warehouse.vulnerabilities.valid\", tags=[f\"origin:{origin}\"])\n\n    try:\n        vulnerability_record = _get_vuln_record(request, report, origin)\n\n        if not report.versions:\n            # No versions indicates the vulnerability is no longer considered\n            # valid, so delete it.\n            _delete_vuln_record(request, vulnerability_record)\n            return\n\n    except NoResultFound:\n        if not report.versions:\n            return\n\n        vulnerability_record = VulnerabilityRecord(\n            id=report.vulnerability_id,\n            source=origin,\n            link=report.advisory_link,\n            aliases=report.aliases,\n        )\n        _add_vuln_record(request, vulnerability_record)\n\n    try:\n        project = _get_project(request, report)\n    except NoResultFound:\n        metrics.increment(\n            \"warehouse.vulnerabilities.error.project_not_found\",\n            tags=[f\"origin:{origin}\"],\n        )\n        raise\n\n    for version in report.versions:\n        try:\n            release = _get_release(request, project, version)\n        except NoResultFound:\n            metrics.increment(\n                \"warehouse.vulnerabilities.error.release_not_found\",\n                tags=[f\"origin:{origin}\"],\n            )\n            raise\n\n        if release not in vulnerability_record.releases:\n            vulnerability_record.releases.append(release)\n\n    # Unassociate any releases that no longer apply.\n    for release in list(vulnerability_record.releases):\n        if release.version not in report.versions:\n            vulnerability_record.releases.remove(release)\n\n\ndef analyze_vulnerability(request, vulnerability_report, origin, metrics):\n    metrics.increment(\"warehouse.vulnerabilities.received\", tags=[f\"origin:{origin}\"])\n    try:\n        with metrics.timed(\n            \"warehouse.vulnerabilities.analysis\", tags=[f\"origin:{origin}\"]\n        ):\n            _analyze_vulnerability(\n                request=request,\n                vulnerability_report=vulnerability_report,\n                origin=origin,\n                metrics=metrics,\n            )\n\n        metrics.increment(\n            \"warehouse.vulnerabilities.processed\", tags=[f\"origin:{origin}\"]\n        )\n    except (vulnerabilities.InvalidVulnerabilityReportRequest, NoResultFound):\n        raise\n    except Exception:\n        metrics.increment(\n            \"warehouse.vulnerabilities.error.unknown\", tags=[f\"origin:{origin}\"]\n        )\n        raise\n\n\ndef analyze_vulnerabilities(request, vulnerability_reports, origin, metrics):\n    from warehouse.integrations.vulnerabilities import tasks\n\n    if not isinstance(vulnerability_reports, list):\n        metrics.increment(\n            \"warehouse.vulnerabilities.error.format\", tags=[f\"origin:{origin}\"]\n        )\n        raise vulnerabilities.InvalidVulnerabilityReportRequest(\n            \"Invalid format: payload is not a list\", \"format\"\n        )\n\n    for vulnerability_report in vulnerability_reports:\n        request.task(tasks.analyze_vulnerability_task).delay(\n            vulnerability_report=vulnerability_report,\n            origin=origin,\n        )\n", "path": "warehouse/integrations/vulnerabilities/utils.py"}], "after_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom pyramid.httpexceptions import HTTPBadRequest\nfrom sqlalchemy import func, orm\nfrom sqlalchemy.orm.exc import NoResultFound\n\nfrom warehouse.integrations import vulnerabilities\nfrom warehouse.integrations.vulnerabilities.models import VulnerabilityRecord\nfrom warehouse.packaging.models import Project, Release\n\n\ndef _get_project(request, vuln_report: vulnerabilities.VulnerabilityReportRequest):\n    return (\n        request.db.query(Project)\n        .filter(\n            Project.normalized_name == func.normalize_pep426_name(vuln_report.project)\n        )\n        .one()\n    )\n\n\ndef _get_release(request, project: Project, version):\n    return (\n        request.db.query(Release)\n        .filter(Release.project_id == project.id)\n        .filter(Release.version == version)\n        .one()\n    )\n\n\ndef _get_vuln_record(\n    request, vuln_report: vulnerabilities.VulnerabilityReportRequest, origin\n):\n    return (\n        request.db.query(VulnerabilityRecord)\n        .filter(VulnerabilityRecord.id == vuln_report.vulnerability_id)\n        .filter(VulnerabilityRecord.source == origin)\n        .options(orm.joinedload(VulnerabilityRecord.releases))\n        .one()\n    )\n\n\ndef _delete_vuln_record(request, vuln_record: VulnerabilityRecord):\n    request.db.delete(vuln_record)\n\n\ndef _add_vuln_record(request, vuln_record: VulnerabilityRecord):\n    request.db.add(vuln_record)\n\n\ndef _analyze_vulnerability(request, vulnerability_report, origin, metrics):\n    try:\n        report = vulnerabilities.VulnerabilityReportRequest.from_api_request(\n            request=vulnerability_report\n        )\n    except vulnerabilities.InvalidVulnerabilityReportRequest as exc:\n        metrics.increment(\n            f\"warehouse.vulnerabilities.error.{exc.reason}\", tags=[f\"origin:{origin}\"]\n        )\n        raise\n\n    metrics.increment(\"warehouse.vulnerabilities.valid\", tags=[f\"origin:{origin}\"])\n\n    try:\n        vulnerability_record = _get_vuln_record(request, report, origin)\n\n        if not report.versions:\n            # No versions indicates the vulnerability is no longer considered\n            # valid, so delete it.\n            _delete_vuln_record(request, vulnerability_record)\n            return\n\n    except NoResultFound:\n        if not report.versions:\n            return\n\n        vulnerability_record = VulnerabilityRecord(\n            id=report.vulnerability_id,\n            source=origin,\n            link=report.advisory_link,\n            aliases=report.aliases,\n        )\n        _add_vuln_record(request, vulnerability_record)\n\n    try:\n        project = _get_project(request, report)\n    except NoResultFound:\n        metrics.increment(\n            \"warehouse.vulnerabilities.error.project_not_found\",\n            tags=[f\"origin:{origin}\"],\n        )\n        raise\n\n    found_releases = False  # by now, we don't have any release found\n\n    for version in report.versions:\n        try:\n            release = _get_release(request, project, version)\n            found_releases = True  # at least one release found\n        except NoResultFound:\n            metrics.increment(\n                \"warehouse.vulnerabilities.error.release_not_found\",\n                tags=[f\"origin:{origin}\"],\n            )\n            continue  # skip that release\n\n        if release not in vulnerability_record.releases:\n            vulnerability_record.releases.append(release)\n\n    if not found_releases:\n        # no releases found, then raise an exception\n        raise HTTPBadRequest(\"None of the releases were found\")\n\n    # Unassociate any releases that no longer apply.\n    for release in list(vulnerability_record.releases):\n        if release.version not in report.versions:\n            vulnerability_record.releases.remove(release)\n\n\ndef analyze_vulnerability(request, vulnerability_report, origin, metrics):\n    metrics.increment(\"warehouse.vulnerabilities.received\", tags=[f\"origin:{origin}\"])\n    try:\n        with metrics.timed(\n            \"warehouse.vulnerabilities.analysis\", tags=[f\"origin:{origin}\"]\n        ):\n            _analyze_vulnerability(\n                request=request,\n                vulnerability_report=vulnerability_report,\n                origin=origin,\n                metrics=metrics,\n            )\n\n        metrics.increment(\n            \"warehouse.vulnerabilities.processed\", tags=[f\"origin:{origin}\"]\n        )\n    except (\n        vulnerabilities.InvalidVulnerabilityReportRequest,\n        NoResultFound,\n        HTTPBadRequest,\n    ):\n        raise\n    except Exception:\n        metrics.increment(\n            \"warehouse.vulnerabilities.error.unknown\", tags=[f\"origin:{origin}\"]\n        )\n        raise\n\n\ndef analyze_vulnerabilities(request, vulnerability_reports, origin, metrics):\n    from warehouse.integrations.vulnerabilities import tasks\n\n    if not isinstance(vulnerability_reports, list):\n        metrics.increment(\n            \"warehouse.vulnerabilities.error.format\", tags=[f\"origin:{origin}\"]\n        )\n        raise vulnerabilities.InvalidVulnerabilityReportRequest(\n            \"Invalid format: payload is not a list\", \"format\"\n        )\n\n    for vulnerability_report in vulnerability_reports:\n        request.task(tasks.analyze_vulnerability_task).delay(\n            vulnerability_report=vulnerability_report,\n            origin=origin,\n        )\n", "path": "warehouse/integrations/vulnerabilities/utils.py"}]}