Skip to content

Commit cc0b96d

Browse files
woodruffwDarkaMauldi
authored
warehouse: PEP 740 models (#16625)
* warehouse: PEP 740 models This is a breakout from #16624, to reduce the complexity/headache of zippered reverts. Signed-off-by: William Woodruff <[email protected]> * tests: AttestationFactory helper Signed-off-by: William Woodruff <[email protected]> * tests: attestation coverage Signed-off-by: William Woodruff <[email protected]> * switch to a Provenance model Signed-off-by: William Woodruff <[email protected]> * provenance model carries a digest Signed-off-by: William Woodruff <[email protected]> * remove unused factory Signed-off-by: William Woodruff <[email protected]> * use SHA-256 for provenance digest Signed-off-by: William Woodruff <[email protected]> * mark provenance column as deferred Signed-off-by: William Woodruff <[email protected]> * Add a ProvenanceFactory object and a simple test. * Revert "Add a ProvenanceFactory object and a simple test." This reverts commit 34ec661. * Update warehouse/packaging/models.py --------- Signed-off-by: William Woodruff <[email protected]> Co-authored-by: Alexis <[email protected]> Co-authored-by: Dustin Ingram <[email protected]>
1 parent 8947dd8 commit cc0b96d

File tree

5 files changed

+130
-0
lines changed

5 files changed

+130
-0
lines changed

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.

warehouse/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.

warehouse/attestations/models.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
from __future__ import annotations
13+
14+
import typing
15+
16+
from uuid import UUID
17+
18+
from sqlalchemy import ForeignKey, orm
19+
from sqlalchemy.dialects.postgresql import CITEXT, JSONB
20+
from sqlalchemy.orm import Mapped, mapped_column
21+
22+
from warehouse import db
23+
24+
if typing.TYPE_CHECKING:
25+
from warehouse.packaging.models import File
26+
27+
28+
class Provenance(db.Model):
29+
"""
30+
A table for PEP 740 provenance objects.
31+
32+
Provenance objects contain one or more attestation objects.
33+
These attestation objects are grouped into "bundles," each of which
34+
contains one or more attestations along with the Trusted Publisher
35+
identity that produced them.
36+
"""
37+
38+
__tablename__ = "provenance"
39+
40+
file_id: Mapped[UUID] = mapped_column(
41+
ForeignKey("release_files.id", onupdate="CASCADE", ondelete="CASCADE"),
42+
)
43+
file: Mapped[File] = orm.relationship(back_populates="provenance")
44+
45+
# This JSONB has the structure of a PEP 740 provenance object.
46+
provenance: Mapped[dict] = mapped_column(JSONB, nullable=False, deferred=True)
47+
48+
# The SHA-2/256 digest of the provenance object stored in this row.
49+
# Postgres uses a compact binary representation under the hood and is
50+
# unlikely to provide a permanently stable serialization, so this is the
51+
# hash of the RFC 8785 serialization.
52+
provenance_digest: Mapped[str] = mapped_column(CITEXT)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
add provenance table
14+
15+
Revision ID: 1b9ae6ec6ec0
16+
Revises: dcf1e3986782
17+
Create Date: 2024-09-03 23:39:30.853147
18+
"""
19+
20+
import sqlalchemy as sa
21+
22+
from alembic import op
23+
from sqlalchemy.dialects import postgresql
24+
25+
revision = "1b9ae6ec6ec0"
26+
down_revision = "dcf1e3986782"
27+
28+
29+
def upgrade():
30+
op.create_table(
31+
"provenance",
32+
sa.Column("file_id", sa.UUID(), nullable=False),
33+
sa.Column(
34+
"provenance", postgresql.JSONB(astext_type=sa.Text()), nullable=False
35+
),
36+
sa.Column("provenance_digest", postgresql.CITEXT(), nullable=False),
37+
sa.Column(
38+
"id", sa.UUID(), server_default=sa.text("gen_random_uuid()"), nullable=False
39+
),
40+
sa.ForeignKeyConstraint(
41+
["file_id"], ["release_files.id"], onupdate="CASCADE", ondelete="CASCADE"
42+
),
43+
sa.PrimaryKeyConstraint("id"),
44+
)
45+
46+
47+
def downgrade():
48+
op.drop_table("provenance")

warehouse/packaging/models.py

+8
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262

6363
from warehouse import db
6464
from warehouse.accounts.models import User
65+
from warehouse.attestations.models import Provenance
6566
from warehouse.authnz import Permissions
6667
from warehouse.classifiers.models import Classifier
6768
from warehouse.events.models import HasEvents
@@ -839,6 +840,13 @@ def __table_args__(cls): # noqa
839840
comment="If True, the metadata for the file cannot be backfilled.",
840841
)
841842

843+
# PEP 740
844+
provenance: Mapped[Provenance] = orm.relationship(
845+
cascade="all, delete-orphan",
846+
lazy="joined",
847+
passive_deletes=True,
848+
)
849+
842850
@property
843851
def uploaded_via_trusted_publisher(self) -> bool:
844852
"""Return True if the file was uploaded via a trusted publisher."""

0 commit comments

Comments
 (0)