#1127133 python-tuf: will FTBFS during forky support period

#1127133#5
Date:
2026-02-06 12:02:55 UTC
From:
To:
Dear maintainer:

During a rebuild of all packages in unstable with the system clock set
at 2030-08-09 (estimated to be three years after the release date of forky),
this package failed to build.

Below you will find the last part of the build log (probably the most
relevant part, but not necessarily). If required, the full build log
is available here:

https://people.debian.org/~sanvila/build-logs/ftbfs-future/

About the archive rebuild: This is an effort to keep forky free from
FTBFS bugs during its lifetime as a supported distribution, as
explained here for trixie:

https://lists.debian.org/debian-devel/2024/05/msg00414.html

This category of bugs is considered to be RC for forky, but I will
wait two months from now before raising to serious to give people a
little bit more time to fix them.

The build was made using sbuild and a reduced chroot with only
build-essential packages.

If you cannot reproduce the bug please contact me privately, as I
am willing to provide ssh access to a virtual machine where the bug is
fully reproducible.

If this is really a bug in one of the build-depends, please use
reassign and add an affects on src:python-tuf, so that this is still
visible in the BTS web page for this package.

Thanks.
--------------------------------------------------------------------------------
[...]
        """Verify and load ``data`` as new timestamp metadata.

        Note that an intermediate timestamp is allowed to be expired:
        ``TrustedMetadataSet`` will throw an ``ExpiredMetadataError`` in
        this case but the intermediate timestamp will be loaded. This way
        a newer timestamp can still be loaded (and the intermediate
        timestamp will be used for rollback protection). Expired timestamp
        will prevent loading snapshot metadata.

        Args:
            data: Unverified new timestamp metadata as bytes

        Raises:
            RuntimeError: This function is called after updating snapshot.
            RepositoryError: Metadata failed to load or verify as final
                timestamp. The actual error type and content will contain
                more details.

        Returns:
            Deserialized and verified ``Timestamp`` object
        """
        if Snapshot.type in self._trusted_set:
            raise RuntimeError("Cannot update timestamp after snapshot")

        # client workflow 5.3.10: Make sure final root is not expired.
        if self.root.is_expired(self.reference_time):
tuf/ngclient/_internal/trusted_metadata_set.py:231: ExpiredMetadataError

tests/test_trusted_metadata_set.py:344:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    def update_snapshot(
        self, data: bytes, trusted: bool | None = False
    ) -> Snapshot:
        """Verify and load ``data`` as new snapshot metadata.

        Note that an intermediate snapshot is allowed to be expired and version
        is allowed to not match timestamp meta version: ``TrustedMetadataSet``
        will throw an ``ExpiredMetadataError``/``BadVersionNumberError`` in
        these cases but the intermediate snapshot will be loaded. This way a
        newer snapshot can still be loaded (and the intermediate snapshot will
        be used for rollback protection). Expired snapshot or snapshot that
        does not match timestamp meta version will prevent loading targets.

        Args:
            data: Unverified new snapshot metadata as bytes
            trusted: ``True`` if data has at some point been verified by
                ``TrustedMetadataSet`` as a valid snapshot. Purpose of trusted
                is to allow loading of locally stored snapshot as intermediate
                snapshot even if hashes in current timestamp meta no longer
                match data. Default is False.

        Raises:
            RuntimeError: This function is called before updating timestamp
                or after updating targets.
            RepositoryError: Data failed to load or verify as final snapshot.
                The actual error type and content will contain more details.

        Returns:
            Deserialized and verified ``Snapshot`` object
        """

        if Timestamp.type not in self._trusted_set:
tuf/ngclient/_internal/trusted_metadata_set.py:308: RuntimeError
_ TestTrustedMetadataSet.test_update_timestamp_new_timestamp_ver_below_trusted_ver _

self = <tests.test_trusted_metadata_set.TestTrustedMetadataSet testMethod=test_update_timestamp_new_timestamp_ver_below_trusted_ver>

    def test_update_timestamp_new_timestamp_ver_below_trusted_ver(self) -> None:
        # new_timestamp.version < trusted_timestamp.version
        def version_modifier(timestamp: Timestamp) -> None:
            timestamp.version = 3

        timestamp = self.modify_metadata(Timestamp.type, version_modifier)

tests/test_trusted_metadata_set.py:298:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <tuf.ngclient._internal.trusted_metadata_set.TrustedMetadataSet object at 0x7f135dd68cb0>
data = b'{\n "signatures": [\n  {\n   "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758",\n   "sig":...,\n  "meta": {\n   "snapshot.json": {\n    "version": 1\n   }\n  },\n  "spec_version": "1.0.0",\n  "version": 3\n }\n}'

    def update_timestamp(self, data: bytes) -> Timestamp:
        """Verify and load ``data`` as new timestamp metadata.

        Note that an intermediate timestamp is allowed to be expired:
        ``TrustedMetadataSet`` will throw an ``ExpiredMetadataError`` in
        this case but the intermediate timestamp will be loaded. This way
        a newer timestamp can still be loaded (and the intermediate
        timestamp will be used for rollback protection). Expired timestamp
        will prevent loading snapshot metadata.

        Args:
            data: Unverified new timestamp metadata as bytes

        Raises:
            RuntimeError: This function is called after updating snapshot.
            RepositoryError: Metadata failed to load or verify as final
                timestamp. The actual error type and content will contain
                more details.

        Returns:
            Deserialized and verified ``Timestamp`` object
        """
        if Snapshot.type in self._trusted_set:
            raise RuntimeError("Cannot update timestamp after snapshot")

        # client workflow 5.3.10: Make sure final root is not expired.
        if self.root.is_expired(self.reference_time):
tuf/ngclient/_internal/trusted_metadata_set.py:231: ExpiredMetadataError
___ TestTrustedMetadataSet.test_update_timestamp_snapshot_ver_below_current ____

self = <tests.test_trusted_metadata_set.TestTrustedMetadataSet testMethod=test_update_timestamp_snapshot_ver_below_current>

    def test_update_timestamp_snapshot_ver_below_current(self) -> None:
        def bump_snapshot_version(timestamp: Timestamp) -> None:
            timestamp.snapshot_meta.version = 2
            # The timestamp version must be increased to initiate a update.
            timestamp.version += 1

        # set current known snapshot.json version to 2
        timestamp = self.modify_metadata(Timestamp.type, bump_snapshot_version)

tests/test_trusted_metadata_set.py:324:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <tuf.ngclient._internal.trusted_metadata_set.TrustedMetadataSet object at 0x7f135dd69610>
data = b'{\n "signatures": [\n  {\n   "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758",\n   "sig":...,\n  "meta": {\n   "snapshot.json": {\n    "version": 2\n   }\n  },\n  "spec_version": "1.0.0",\n  "version": 2\n }\n}'

    def update_timestamp(self, data: bytes) -> Timestamp:
        """Verify and load ``data`` as new timestamp metadata.

        Note that an intermediate timestamp is allowed to be expired:
        ``TrustedMetadataSet`` will throw an ``ExpiredMetadataError`` in
        this case but the intermediate timestamp will be loaded. This way
        a newer timestamp can still be loaded (and the intermediate
        timestamp will be used for rollback protection). Expired timestamp
        will prevent loading snapshot metadata.

        Args:
            data: Unverified new timestamp metadata as bytes

        Raises:
            RuntimeError: This function is called after updating snapshot.
            RepositoryError: Metadata failed to load or verify as final
                timestamp. The actual error type and content will contain
                more details.

        Returns:
            Deserialized and verified ``Timestamp`` object
        """
        if Snapshot.type in self._trusted_set:
            raise RuntimeError("Cannot update timestamp after snapshot")

        # client workflow 5.3.10: Make sure final root is not expired.
        if self.root.is_expired(self.reference_time):
tuf/ngclient/_internal/trusted_metadata_set.py:231: ExpiredMetadataError
_______ TestTrustedMetadataSet.test_update_timestamp_with_same_timestamp _______

self = <tests.test_trusted_metadata_set.TestTrustedMetadataSet testMethod=test_update_timestamp_with_same_timestamp>

    def test_update_timestamp_with_same_timestamp(self) -> None:
        # Test that timestamp is NOT updated if:
        # new_timestamp.version == trusted_timestamp.version

tests/test_trusted_metadata_set.py:305:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <tuf.ngclient._internal.trusted_metadata_set.TrustedMetadataSet object at 0x7f135dd69c10>
data = b'{\n "signatures": [\n  {\n   "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758",\n   "sig":...,\n  "meta": {\n   "snapshot.json": {\n    "version": 1\n   }\n  },\n  "spec_version": "1.0.0",\n  "version": 1\n }\n}'

    def update_timestamp(self, data: bytes) -> Timestamp:
        """Verify and load ``data`` as new timestamp metadata.

        Note that an intermediate timestamp is allowed to be expired:
        ``TrustedMetadataSet`` will throw an ``ExpiredMetadataError`` in
        this case but the intermediate timestamp will be loaded. This way
        a newer timestamp can still be loaded (and the intermediate
        timestamp will be used for rollback protection). Expired timestamp
        will prevent loading snapshot metadata.

        Args:
            data: Unverified new timestamp metadata as bytes

        Raises:
            RuntimeError: This function is called after updating snapshot.
            RepositoryError: Metadata failed to load or verify as final
                timestamp. The actual error type and content will contain
                more details.

        Returns:
            Deserialized and verified ``Timestamp`` object
        """
        if Snapshot.type in self._trusted_set:
            raise RuntimeError("Cannot update timestamp after snapshot")

        # client workflow 5.3.10: Make sure final root is not expired.
        if self.root.is_expired(self.reference_time):
tuf/ngclient/_internal/trusted_metadata_set.py:231: ExpiredMetadataError
=============================== warnings summary ===============================
tests/test_repository.py:42
  /<<PKGBUILDDIR>>/.pybuild/cpython3_3.13/build/tests/test_repository.py:42: PytestCollectionWarning: cannot collect test class 'TestingRepository' because it has a __init__ constructor (from: tests/test_repository.py)
    class TestingRepository(Repository):

tests/test_updater_delegation_graphs.py:31
  /<<PKGBUILDDIR>>/.pybuild/cpython3_3.13/build/tests/test_updater_delegation_graphs.py:31: PytestCollectionWarning: cannot collect test class 'TestDelegation' because it has a __init__ constructor (from: tests/test_updater_delegation_graphs.py)
    @dataclass

tests/test_updater_delegation_graphs.py:42
  /<<PKGBUILDDIR>>/.pybuild/cpython3_3.13/build/tests/test_updater_delegation_graphs.py:42: PytestCollectionWarning: cannot collect test class 'TestTarget' because it has a __init__ constructor (from: tests/test_updater_delegation_graphs.py)
    @dataclass

tests/test_updater_fetch_target.py:23
  /<<PKGBUILDDIR>>/.pybuild/cpython3_3.13/build/tests/test_updater_fetch_target.py:23: PytestCollectionWarning: cannot collect test class 'TestTarget' because it has a __init__ constructor (from: tests/test_updater_fetch_target.py)
    @dataclass