Skip to content

Commit 5545884

Browse files
DarkaMauldiwoodruffw
authored
Store attestations for PEP740 (#16302)
* Store and retrieve attestations * Continue to work. * Update attestation storage and retrieval * Update comments * Fix import * Please linter * Use the correct event to attach a publisher_url to a `File` * Rename ReleaseFileAttestation to Attestation * Update names * Update table migration * Update metrics * Update attestations storage * Update pypi-attestations and sigstore dependencies * Fix wrong merge. * Generate Provenance file on upload. * Generate and store provenance file during upload. * Improve tests * Fix test error * Fix test error * Fix merge error * Simplify legacy answer * Introduce AttestationsService * Rename AttestationsService to ReleaseVerification service and integrate Provenance related objects * Remove useless check * Integrate generate_and_store_provenance within persist_attestations * Remove file.publisher_url which is no longer used. * Rename ReleaseAttestationService to IntegrityService * Linting * requirements: bump sigstore, pypi-attestations Signed-off-by: William Woodruff <[email protected]> --------- Signed-off-by: William Woodruff <[email protected]> Co-authored-by: Dustin Ingram <[email protected]> Co-authored-by: William Woodruff <[email protected]>
1 parent 54fda81 commit 5545884

File tree

19 files changed

+1063
-474
lines changed

19 files changed

+1063
-474
lines changed

requirements/main.in

+2-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ redis>=2.8.0,<6.0.0
6262
rfc3986
6363
sentry-sdk
6464
setuptools
65-
sigstore~=3.0.0
66-
pypi-attestations==0.0.9
65+
sigstore~=3.2.0
66+
pypi-attestations==0.0.11
6767
sqlalchemy[asyncio]>=2.0,<3.0
6868
stdlib-list
6969
stripe

requirements/main.txt

+6-6
Original file line numberDiff line numberDiff line change
@@ -1770,9 +1770,9 @@ pyparsing==3.1.2 \
17701770
--hash=sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad \
17711771
--hash=sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742
17721772
# via linehaul
1773-
pypi-attestations==0.0.9 \
1774-
--hash=sha256:3bfc07f64a8db0d6e2646720e70df7c7cb01a2936056c764a2cc3268969332f2 \
1775-
--hash=sha256:4b38cce5d221c8145cac255bfafe650ec0028d924d2b3572394df8ba8f07a609
1773+
pypi-attestations==0.0.11 \
1774+
--hash=sha256:b730e6b23874d94da0f3817b1f9dd3ecb6a80d685f62a18ad96e5b0396149ded \
1775+
--hash=sha256:e74329074f049568591e300373e12fcd46a35e21723110856546e33bf2949efa
17761776
# via -r requirements/main.in
17771777
pyqrcode==1.2.1 \
17781778
--hash=sha256:1b2812775fa6ff5c527977c4cd2ccb07051ca7d0bc0aecf937a43864abe5eff6 \
@@ -2079,9 +2079,9 @@ sentry-sdk==2.13.0 \
20792079
--hash=sha256:6beede8fc2ab4043da7f69d95534e320944690680dd9a963178a49de71d726c6 \
20802080
--hash=sha256:8d4a576f7a98eb2fdb40e13106e41f330e5c79d72a68be1316e7852cf4995260
20812081
# via -r requirements/main.in
2082-
sigstore==3.0.0 \
2083-
--hash=sha256:6cc7dc92607c2fd481aada0f3c79e710e4c6086e3beab50b07daa9a50a79d109 \
2084-
--hash=sha256:a6a9538a648e112a0c3d8092d3f73a351c7598164764f1e73a6b5ba406a3a0bd
2082+
sigstore==3.2.0 \
2083+
--hash=sha256:25c8a871a3a6adf959c0cde598ea8bef8794f1a29277d067111eb4ded4ba7f65 \
2084+
--hash=sha256:d18508f34febb7775065855e92557fa1c2c16580df88f8e8903b9514438bad44
20852085
# via
20862086
# -r requirements/main.in
20872087
# pypi-attestations

tests/common/db/attestation.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
import hashlib
13+
14+
import factory
15+
16+
from warehouse.attestations.models import Attestation
17+
18+
from .base import WarehouseFactory
19+
20+
21+
class AttestationFactory(WarehouseFactory):
22+
class Meta:
23+
model = Attestation
24+
25+
file = factory.SubFactory("tests.common.db.packaging.FileFactory")
26+
attestation_file_blake2_digest = factory.LazyAttribute(
27+
lambda o: hashlib.blake2b(o.file.filename.encode("utf8")).hexdigest()
28+
)

tests/common/db/packaging.py

+7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from warehouse.utils import readme
3535

3636
from .accounts import UserFactory
37+
from .attestation import AttestationFactory
3738
from .base import WarehouseFactory
3839
from .observations import ObserverFactory
3940

@@ -140,6 +141,12 @@ class Meta:
140141
)
141142
)
142143

144+
attestations = factory.RelatedFactoryList(
145+
AttestationFactory,
146+
factory_related_name="file",
147+
size=1,
148+
)
149+
143150

144151
class FileEventFactory(WarehouseFactory):
145152
class Meta:

tests/unit/api/test_simple.py

+25
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from pyramid.testing import DummyRequest
1919

2020
from warehouse.api import simple
21+
from warehouse.attestations import IIntegrityService
2122
from warehouse.packaging.utils import API_VERSION
2223

2324
from ...common.db.accounts import UserFactory
@@ -87,6 +88,16 @@ def test_selects(self, header, expected):
8788

8889

8990
class TestSimpleIndex:
91+
92+
@pytest.fixture
93+
def db_request(self, db_request):
94+
"""Override db_request to add the Release Verification service"""
95+
db_request.find_service = lambda svc, name=None, context=None: {
96+
IIntegrityService: pretend.stub(),
97+
}.get(svc)
98+
99+
return db_request
100+
90101
@pytest.mark.parametrize(
91102
("content_type", "renderer_override"),
92103
CONTENT_TYPE_PARAMS,
@@ -185,6 +196,17 @@ def test_quarantined_project_omitted_from_index(self, db_request):
185196

186197

187198
class TestSimpleDetail:
199+
@pytest.fixture
200+
def db_request(self, db_request):
201+
"""Override db_request to add the Release Verification service"""
202+
db_request.find_service = lambda svc, name=None, context=None: {
203+
IIntegrityService: pretend.stub(
204+
get_provenance_digest=lambda *args, **kwargs: None,
205+
),
206+
}.get(svc)
207+
208+
return db_request
209+
188210
def test_redirects(self, pyramid_request):
189211
project = pretend.stub(normalized_name="foo")
190212

@@ -286,6 +308,7 @@ def test_with_files_no_serial(self, db_request, content_type, renderer_override)
286308
"upload-time": f.upload_time.isoformat() + "Z",
287309
"data-dist-info-metadata": False,
288310
"core-metadata": False,
311+
"provenance": None,
289312
}
290313
for f in files
291314
],
@@ -334,6 +357,7 @@ def test_with_files_with_serial(self, db_request, content_type, renderer_overrid
334357
"upload-time": f.upload_time.isoformat() + "Z",
335358
"data-dist-info-metadata": False,
336359
"core-metadata": False,
360+
"provenance": None,
337361
}
338362
for f in files
339363
],
@@ -427,6 +451,7 @@ def test_with_files_with_version_multi_digit(
427451
if f.metadata_file_sha256_digest is not None
428452
else False
429453
),
454+
"provenance": None,
430455
}
431456
for f in files
432457
],

tests/unit/attestations/__init__.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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.

0 commit comments

Comments
 (0)