Skip to content

Add new exceptions file for exceptions in the new code #1725

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jan 20, 2022
2 changes: 1 addition & 1 deletion examples/client_example/client_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import shutil
from pathlib import Path

from tuf.exceptions import RepositoryError
from tuf.api.exceptions import RepositoryError
from tuf.ngclient import Updater

# constants
Expand Down
2 changes: 1 addition & 1 deletion tests/repository_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
from securesystemslib.keys import generate_ed25519_key
from securesystemslib.signer import SSlibSigner

from tuf.api.exceptions import FetcherHTTPError
from tuf.api.metadata import (
SPECIFICATION_VERSION,
TOP_LEVEL_ROLE_NAMES,
Expand All @@ -73,7 +74,6 @@
Timestamp,
)
from tuf.api.serialization.json import JSONSerializer
from tuf.exceptions import FetcherHTTPError
from tuf.ngclient.fetcher import FetcherInterface

logger = logging.getLogger(__name__)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from securesystemslib.signer import Signature, SSlibSigner

from tests import utils
from tuf import exceptions
from tuf.api import exceptions
from tuf.api.metadata import (
TOP_LEVEL_ROLE_NAMES,
DelegatedRole,
Expand Down Expand Up @@ -614,7 +614,7 @@ def test_targetfile_from_file(self) -> None:

# Test with an unsupported algorithm
file_path = os.path.join(self.repo_dir, Targets.type, "file1.txt")
with self.assertRaises(exceptions.UnsupportedAlgorithmError):
with self.assertRaises(ValueError):
TargetFile.from_file(file_path, file_path, ["123"])

def test_targetfile_from_data(self) -> None:
Expand Down
5 changes: 3 additions & 2 deletions tests/test_fetcher_ng.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
import urllib3.exceptions

from tests import utils
from tuf import exceptions, unittest_toolbox
from tuf import unittest_toolbox
from tuf.api import exceptions
from tuf.ngclient._internal.requests_fetcher import RequestsFetcher

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -109,7 +110,7 @@ def test_fetch_in_chunks(self) -> None:

# Incorrect URL parsing
def test_url_parsing(self) -> None:
with self.assertRaises(exceptions.URLParsingError):
with self.assertRaises(exceptions.DownloadError):
self.fetcher.fetch(self.random_string())

# File not found error
Expand Down
8 changes: 4 additions & 4 deletions tests/test_trusted_metadata_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from securesystemslib.signer import SSlibSigner

from tests import utils
from tuf import exceptions
from tuf.api import exceptions
from tuf.api.metadata import (
Metadata,
MetaFile,
Expand Down Expand Up @@ -245,7 +245,7 @@ def test_update_root_new_root_fail_threshold_verification(self) -> None:
self.trusted_set.update_root(root.to_bytes())

def test_update_root_new_root_ver_same_as_trusted_root_ver(self) -> None:
with self.assertRaises(exceptions.ReplayedMetadataError):
with self.assertRaises(exceptions.BadVersionNumberError):
self.trusted_set.update_root(self.metadata[Root.type])

def test_root_expired_final_root(self) -> None:
Expand All @@ -266,7 +266,7 @@ def version_modifier(timestamp: Timestamp) -> None:

timestamp = self.modify_metadata(Timestamp.type, version_modifier)
self.trusted_set.update_timestamp(timestamp)
with self.assertRaises(exceptions.ReplayedMetadataError):
with self.assertRaises(exceptions.BadVersionNumberError):
self.trusted_set.update_timestamp(self.metadata[Timestamp.type])

def test_update_timestamp_snapshot_ver_below_current(self) -> None:
Expand All @@ -278,7 +278,7 @@ def bump_snapshot_version(timestamp: Timestamp) -> None:
self.trusted_set.update_timestamp(timestamp)

# newtimestamp.meta.version < trusted_timestamp.meta.version
with self.assertRaises(exceptions.ReplayedMetadataError):
with self.assertRaises(exceptions.BadVersionNumberError):
self.trusted_set.update_timestamp(self.metadata[Timestamp.type])

def test_update_timestamp_expired(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_updater_delegation_graphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@

from tests import utils
from tests.repository_simulator import RepositorySimulator
from tuf.api.exceptions import UnsignedMetadataError
from tuf.api.metadata import (
SPECIFICATION_VERSION,
TOP_LEVEL_ROLE_NAMES,
DelegatedRole,
Targets,
)
from tuf.exceptions import UnsignedMetadataError
from tuf.ngclient import Updater


Expand Down
2 changes: 1 addition & 1 deletion tests/test_updater_fetch_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from tests import utils
from tests.repository_simulator import RepositorySimulator
from tuf.exceptions import RepositoryError
from tuf.api.exceptions import RepositoryError
from tuf.ngclient import Updater


Expand Down
2 changes: 1 addition & 1 deletion tests/test_updater_key_rotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
from tests import utils
from tests.repository_simulator import RepositorySimulator
from tests.utils import run_sub_tests_with_dataset
from tuf.api.exceptions import UnsignedMetadataError
from tuf.api.metadata import Key, Root
from tuf.exceptions import UnsignedMetadataError
from tuf.ngclient import Updater


Expand Down
3 changes: 2 additions & 1 deletion tests/test_updater_ng.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
from securesystemslib.signer import SSlibSigner

from tests import utils
from tuf import exceptions, ngclient, unittest_toolbox
from tuf import ngclient, unittest_toolbox
from tuf.api import exceptions
from tuf.api.metadata import (
Metadata,
Root,
Expand Down
27 changes: 13 additions & 14 deletions tests/test_updater_top_level_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@

from tests import utils
from tests.repository_simulator import RepositorySimulator
from tuf.api.exceptions import (
BadVersionNumberError,
ExpiredMetadataError,
LengthOrHashMismatchError,
UnsignedMetadataError,
)
from tuf.api.metadata import (
SPECIFICATION_VERSION,
TOP_LEVEL_ROLE_NAMES,
Expand All @@ -26,13 +32,6 @@
Targets,
Timestamp,
)
from tuf.exceptions import (
BadVersionNumberError,
ExpiredMetadataError,
ReplayedMetadataError,
RepositoryError,
UnsignedMetadataError,
)
from tuf.ngclient import Updater


Expand Down Expand Up @@ -267,7 +266,7 @@ def test_new_root_same_version(self) -> None:
# Check for a rollback_attack
# Repository serves a root file with the same version as previous
self.sim.publish_root()
with self.assertRaises(ReplayedMetadataError):
with self.assertRaises(BadVersionNumberError):
self._run_refresh()

# The update failed, latest root version is v1
Expand All @@ -278,7 +277,7 @@ def test_new_root_nonconsecutive_version(self) -> None:
# Repository serves non-consecutive root version
self.sim.root.version += 2
self.sim.publish_root()
with self.assertRaises(ReplayedMetadataError):
with self.assertRaises(BadVersionNumberError):
self._run_refresh()

# The update failed, latest root version is v1
Expand Down Expand Up @@ -313,7 +312,7 @@ def test_new_timestamp_version_rollback(self) -> None:
self._run_refresh()

self.sim.timestamp.version = 1
with self.assertRaises(ReplayedMetadataError):
with self.assertRaises(BadVersionNumberError):
self._run_refresh()

self._assert_version_equals(Timestamp.type, 2)
Expand All @@ -328,7 +327,7 @@ def test_new_timestamp_snapshot_rollback(self) -> None:
self.sim.timestamp.snapshot_meta.version = 1
self.sim.timestamp.version += 1 # timestamp v3

with self.assertRaises(ReplayedMetadataError):
with self.assertRaises(BadVersionNumberError):
self._run_refresh()

self._assert_version_equals(Timestamp.type, 2)
Expand Down Expand Up @@ -390,7 +389,7 @@ def test_new_snapshot_hash_mismatch(self) -> None:
self.sim.timestamp.version += 1 # timestamp v3

# Hash mismatch error
with self.assertRaises(RepositoryError):
with self.assertRaises(LengthOrHashMismatchError):
self._run_refresh()

self._assert_version_equals(Timestamp.type, 3)
Expand Down Expand Up @@ -423,7 +422,7 @@ def test_new_snapshot_version_rollback(self) -> None:
self.sim.snapshot.version = 1
self.sim.update_timestamp()

with self.assertRaises(ReplayedMetadataError):
with self.assertRaises(BadVersionNumberError):
self._run_refresh()

self._assert_version_equals(Snapshot.type, 2)
Expand Down Expand Up @@ -496,7 +495,7 @@ def test_new_targets_hash_mismatch(self) -> None:
self.sim.snapshot.version += 1
self.sim.update_timestamp()

with self.assertRaises(RepositoryError):
with self.assertRaises(LengthOrHashMismatchError):
self._run_refresh()

self._assert_version_equals(Snapshot.type, 3)
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ commands =
# work, unfortunately each subdirectory has to be ignored explicitly.
pylint -j 0 tuf --ignore=tuf/api,tuf/api/serialization,tuf/ngclient,tuf/ngclient/_internal

mypy {[testenv:lint]lint_dirs} tuf/exceptions.py
mypy {[testenv:lint]lint_dirs}

bandit -r tuf

Expand Down
63 changes: 63 additions & 0 deletions tuf/api/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Copyright New York University and the TUF contributors
# SPDX-License-Identifier: MIT OR Apache-2.0

"""
Define TUF exceptions used inside the new modern implementation.
The names chosen for TUF Exception classes should end in 'Error' except where
there is a good reason not to, and provide that reason in those cases.
"""


#### Repository errors ####


class RepositoryError(Exception):
"""An error with a repository's state, such as a missing file.
It covers all exceptions that come from the repository side when
looking from the perspective of users of metadata API or ngclient."""


class UnsignedMetadataError(RepositoryError):
"""An error about metadata object with insufficient threshold of
signatures."""


class BadVersionNumberError(RepositoryError):
"""An error for metadata that contains an invalid version number."""


class ExpiredMetadataError(RepositoryError):
"""Indicate that a TUF Metadata file has expired."""


class LengthOrHashMismatchError(RepositoryError):
"""An error while checking the length and hash values of an object."""


#### Download Errors ####


class DownloadError(Exception):
"""An error occurred while attempting to download a file."""


class DownloadLengthMismatchError(DownloadError):
"""Indicate that a mismatch of lengths was seen while downloading a file."""


class SlowRetrievalError(DownloadError):
"""Indicate that downloading a file took an unreasonably long time."""


class FetcherHTTPError(DownloadError):
"""
Returned by FetcherInterface implementations for HTTP errors.

Args:
message: The HTTP error messsage
status_code: The HTTP status code
"""

def __init__(self, message: str, status_code: int):
super().__init__(message)
self.status_code = status_code
24 changes: 9 additions & 15 deletions tuf/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
from securesystemslib.storage import FilesystemBackend, StorageBackendInterface
from securesystemslib.util import persist_temp_file

from tuf import exceptions
from tuf.api import exceptions
from tuf.api.serialization import (
MetadataDeserializer,
MetadataSerializer,
Expand Down Expand Up @@ -381,7 +381,6 @@ def verify_delegate(
raise exceptions.UnsignedMetadataError(
f"{delegated_role} was signed by {len(signing_keys)}/"
f"{role.threshold} keys",
delegated_metadata.signed,
)


Expand Down Expand Up @@ -623,8 +622,7 @@ def verify_signature(
signature = metadata.signatures[self.keyid]
except KeyError:
raise exceptions.UnsignedMetadataError(
f"no signature for key {self.keyid} found in metadata",
metadata.signed,
f"No signature for key {self.keyid} found in metadata"
) from None

if signed_serializer is None:
Expand All @@ -640,17 +638,15 @@ def verify_signature(
signed_serializer.serialize(metadata.signed),
):
raise exceptions.UnsignedMetadataError(
f"Failed to verify {self.keyid} signature",
metadata.signed,
f"Failed to verify {self.keyid} signature"
)
except (
sslib_exceptions.CryptoError,
sslib_exceptions.FormatError,
sslib_exceptions.UnsupportedAlgorithmError,
) as e:
raise exceptions.UnsignedMetadataError(
f"Failed to verify {self.keyid} signature",
metadata.signed,
f"Failed to verify {self.keyid} signature"
) from e


Expand Down Expand Up @@ -1323,8 +1319,8 @@ def from_file(
specified the securesystemslib default hash algorithm is used.
Raises:
FileNotFoundError: The file doesn't exist.
UnsupportedAlgorithmError: The hash algorithms list
contains an unsupported algorithm.
ValueError: The hash algorithms list contains an unsupported
algorithm.
"""
with open(local_path, "rb") as file:
return cls.from_data(target_file_path, file, hash_algorithms)
Expand All @@ -1346,8 +1342,8 @@ def from_data(
specified the securesystemslib default hash algorithm is used.

Raises:
UnsupportedAlgorithmError: The hash algorithms list
contains an unsupported algorithm.
ValueError: The hash algorithms list contains an unsupported
algorithm.
"""
if isinstance(data, bytes):
length = len(data)
Expand All @@ -1373,9 +1369,7 @@ def from_data(
sslib_exceptions.UnsupportedAlgorithmError,
sslib_exceptions.FormatError,
) as e:
raise exceptions.UnsupportedAlgorithmError(
f"Unsupported algorithm '{algorithm}'"
) from e
raise ValueError(f"Unsupported algorithm '{algorithm}'") from e

hashes[algorithm] = digest_object.hexdigest()

Expand Down
Loading