Skip to content

Commit 1e4590b

Browse files
authored
Merge pull request #1725 from MVrachev/new-exceptions.py
Add new exceptions file for exceptions in the new code
2 parents 0e26364 + 7bb916f commit 1e4590b

18 files changed

+141
-108
lines changed

examples/client_example/client_example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import shutil
1111
from pathlib import Path
1212

13-
from tuf.exceptions import RepositoryError
13+
from tuf.api.exceptions import RepositoryError
1414
from tuf.ngclient import Updater
1515

1616
# constants

tests/repository_simulator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
from securesystemslib.keys import generate_ed25519_key
5858
from securesystemslib.signer import SSlibSigner
5959

60+
from tuf.api.exceptions import FetcherHTTPError
6061
from tuf.api.metadata import (
6162
SPECIFICATION_VERSION,
6263
TOP_LEVEL_ROLE_NAMES,
@@ -73,7 +74,6 @@
7374
Timestamp,
7475
)
7576
from tuf.api.serialization.json import JSONSerializer
76-
from tuf.exceptions import FetcherHTTPError
7777
from tuf.ngclient.fetcher import FetcherInterface
7878

7979
logger = logging.getLogger(__name__)

tests/test_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from securesystemslib.signer import Signature, SSlibSigner
2626

2727
from tests import utils
28-
from tuf import exceptions
28+
from tuf.api import exceptions
2929
from tuf.api.metadata import (
3030
TOP_LEVEL_ROLE_NAMES,
3131
DelegatedRole,
@@ -614,7 +614,7 @@ def test_targetfile_from_file(self) -> None:
614614

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

620620
def test_targetfile_from_data(self) -> None:

tests/test_fetcher_ng.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
import urllib3.exceptions
2121

2222
from tests import utils
23-
from tuf import exceptions, unittest_toolbox
23+
from tuf import unittest_toolbox
24+
from tuf.api import exceptions
2425
from tuf.ngclient._internal.requests_fetcher import RequestsFetcher
2526

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

110111
# Incorrect URL parsing
111112
def test_url_parsing(self) -> None:
112-
with self.assertRaises(exceptions.URLParsingError):
113+
with self.assertRaises(exceptions.DownloadError):
113114
self.fetcher.fetch(self.random_string())
114115

115116
# File not found error

tests/test_trusted_metadata_set.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from securesystemslib.signer import SSlibSigner
1414

1515
from tests import utils
16-
from tuf import exceptions
16+
from tuf.api import exceptions
1717
from tuf.api.metadata import (
1818
Metadata,
1919
MetaFile,
@@ -245,7 +245,7 @@ def test_update_root_new_root_fail_threshold_verification(self) -> None:
245245
self.trusted_set.update_root(root.to_bytes())
246246

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

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

267267
timestamp = self.modify_metadata(Timestamp.type, version_modifier)
268268
self.trusted_set.update_timestamp(timestamp)
269-
with self.assertRaises(exceptions.ReplayedMetadataError):
269+
with self.assertRaises(exceptions.BadVersionNumberError):
270270
self.trusted_set.update_timestamp(self.metadata[Timestamp.type])
271271

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

280280
# newtimestamp.meta.version < trusted_timestamp.meta.version
281-
with self.assertRaises(exceptions.ReplayedMetadataError):
281+
with self.assertRaises(exceptions.BadVersionNumberError):
282282
self.trusted_set.update_timestamp(self.metadata[Timestamp.type])
283283

284284
def test_update_timestamp_expired(self) -> None:

tests/test_updater_delegation_graphs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515

1616
from tests import utils
1717
from tests.repository_simulator import RepositorySimulator
18+
from tuf.api.exceptions import UnsignedMetadataError
1819
from tuf.api.metadata import (
1920
SPECIFICATION_VERSION,
2021
TOP_LEVEL_ROLE_NAMES,
2122
DelegatedRole,
2223
Targets,
2324
)
24-
from tuf.exceptions import UnsignedMetadataError
2525
from tuf.ngclient import Updater
2626

2727

tests/test_updater_fetch_target.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from tests import utils
1717
from tests.repository_simulator import RepositorySimulator
18-
from tuf.exceptions import RepositoryError
18+
from tuf.api.exceptions import RepositoryError
1919
from tuf.ngclient import Updater
2020

2121

tests/test_updater_key_rotations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
from tests import utils
1818
from tests.repository_simulator import RepositorySimulator
1919
from tests.utils import run_sub_tests_with_dataset
20+
from tuf.api.exceptions import UnsignedMetadataError
2021
from tuf.api.metadata import Key, Root
21-
from tuf.exceptions import UnsignedMetadataError
2222
from tuf.ngclient import Updater
2323

2424

tests/test_updater_ng.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
from securesystemslib.signer import SSlibSigner
2020

2121
from tests import utils
22-
from tuf import exceptions, ngclient, unittest_toolbox
22+
from tuf import ngclient, unittest_toolbox
23+
from tuf.api import exceptions
2324
from tuf.api.metadata import (
2425
Metadata,
2526
Root,

tests/test_updater_top_level_update.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616

1717
from tests import utils
1818
from tests.repository_simulator import RepositorySimulator
19+
from tuf.api.exceptions import (
20+
BadVersionNumberError,
21+
ExpiredMetadataError,
22+
LengthOrHashMismatchError,
23+
UnsignedMetadataError,
24+
)
1925
from tuf.api.metadata import (
2026
SPECIFICATION_VERSION,
2127
TOP_LEVEL_ROLE_NAMES,
@@ -26,13 +32,6 @@
2632
Targets,
2733
Timestamp,
2834
)
29-
from tuf.exceptions import (
30-
BadVersionNumberError,
31-
ExpiredMetadataError,
32-
ReplayedMetadataError,
33-
RepositoryError,
34-
UnsignedMetadataError,
35-
)
3635
from tuf.ngclient import Updater
3736

3837

@@ -267,7 +266,7 @@ def test_new_root_same_version(self) -> None:
267266
# Check for a rollback_attack
268267
# Repository serves a root file with the same version as previous
269268
self.sim.publish_root()
270-
with self.assertRaises(ReplayedMetadataError):
269+
with self.assertRaises(BadVersionNumberError):
271270
self._run_refresh()
272271

273272
# The update failed, latest root version is v1
@@ -278,7 +277,7 @@ def test_new_root_nonconsecutive_version(self) -> None:
278277
# Repository serves non-consecutive root version
279278
self.sim.root.version += 2
280279
self.sim.publish_root()
281-
with self.assertRaises(ReplayedMetadataError):
280+
with self.assertRaises(BadVersionNumberError):
282281
self._run_refresh()
283282

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

315314
self.sim.timestamp.version = 1
316-
with self.assertRaises(ReplayedMetadataError):
315+
with self.assertRaises(BadVersionNumberError):
317316
self._run_refresh()
318317

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

331-
with self.assertRaises(ReplayedMetadataError):
330+
with self.assertRaises(BadVersionNumberError):
332331
self._run_refresh()
333332

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

392391
# Hash mismatch error
393-
with self.assertRaises(RepositoryError):
392+
with self.assertRaises(LengthOrHashMismatchError):
394393
self._run_refresh()
395394

396395
self._assert_version_equals(Timestamp.type, 3)
@@ -423,7 +422,7 @@ def test_new_snapshot_version_rollback(self) -> None:
423422
self.sim.snapshot.version = 1
424423
self.sim.update_timestamp()
425424

426-
with self.assertRaises(ReplayedMetadataError):
425+
with self.assertRaises(BadVersionNumberError):
427426
self._run_refresh()
428427

429428
self._assert_version_equals(Snapshot.type, 2)
@@ -496,7 +495,7 @@ def test_new_targets_hash_mismatch(self) -> None:
496495
self.sim.snapshot.version += 1
497496
self.sim.update_timestamp()
498497

499-
with self.assertRaises(RepositoryError):
498+
with self.assertRaises(LengthOrHashMismatchError):
500499
self._run_refresh()
501500

502501
self._assert_version_equals(Snapshot.type, 3)

tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ commands =
4949
# work, unfortunately each subdirectory has to be ignored explicitly.
5050
pylint -j 0 tuf --ignore=tuf/api,tuf/api/serialization,tuf/ngclient,tuf/ngclient/_internal
5151

52-
mypy {[testenv:lint]lint_dirs} tuf/exceptions.py
52+
mypy {[testenv:lint]lint_dirs}
5353

5454
bandit -r tuf
5555

tuf/api/exceptions.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright New York University and the TUF contributors
2+
# SPDX-License-Identifier: MIT OR Apache-2.0
3+
4+
"""
5+
Define TUF exceptions used inside the new modern implementation.
6+
The names chosen for TUF Exception classes should end in 'Error' except where
7+
there is a good reason not to, and provide that reason in those cases.
8+
"""
9+
10+
11+
#### Repository errors ####
12+
13+
14+
class RepositoryError(Exception):
15+
"""An error with a repository's state, such as a missing file.
16+
It covers all exceptions that come from the repository side when
17+
looking from the perspective of users of metadata API or ngclient."""
18+
19+
20+
class UnsignedMetadataError(RepositoryError):
21+
"""An error about metadata object with insufficient threshold of
22+
signatures."""
23+
24+
25+
class BadVersionNumberError(RepositoryError):
26+
"""An error for metadata that contains an invalid version number."""
27+
28+
29+
class ExpiredMetadataError(RepositoryError):
30+
"""Indicate that a TUF Metadata file has expired."""
31+
32+
33+
class LengthOrHashMismatchError(RepositoryError):
34+
"""An error while checking the length and hash values of an object."""
35+
36+
37+
#### Download Errors ####
38+
39+
40+
class DownloadError(Exception):
41+
"""An error occurred while attempting to download a file."""
42+
43+
44+
class DownloadLengthMismatchError(DownloadError):
45+
"""Indicate that a mismatch of lengths was seen while downloading a file."""
46+
47+
48+
class SlowRetrievalError(DownloadError):
49+
"""Indicate that downloading a file took an unreasonably long time."""
50+
51+
52+
class FetcherHTTPError(DownloadError):
53+
"""
54+
Returned by FetcherInterface implementations for HTTP errors.
55+
56+
Args:
57+
message: The HTTP error messsage
58+
status_code: The HTTP status code
59+
"""
60+
61+
def __init__(self, message: str, status_code: int):
62+
super().__init__(message)
63+
self.status_code = status_code

tuf/api/metadata.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
from securesystemslib.storage import FilesystemBackend, StorageBackendInterface
5858
from securesystemslib.util import persist_temp_file
5959

60-
from tuf import exceptions
60+
from tuf.api import exceptions
6161
from tuf.api.serialization import (
6262
MetadataDeserializer,
6363
MetadataSerializer,
@@ -381,7 +381,6 @@ def verify_delegate(
381381
raise exceptions.UnsignedMetadataError(
382382
f"{delegated_role} was signed by {len(signing_keys)}/"
383383
f"{role.threshold} keys",
384-
delegated_metadata.signed,
385384
)
386385

387386

@@ -623,8 +622,7 @@ def verify_signature(
623622
signature = metadata.signatures[self.keyid]
624623
except KeyError:
625624
raise exceptions.UnsignedMetadataError(
626-
f"no signature for key {self.keyid} found in metadata",
627-
metadata.signed,
625+
f"No signature for key {self.keyid} found in metadata"
628626
) from None
629627

630628
if signed_serializer is None:
@@ -640,17 +638,15 @@ def verify_signature(
640638
signed_serializer.serialize(metadata.signed),
641639
):
642640
raise exceptions.UnsignedMetadataError(
643-
f"Failed to verify {self.keyid} signature",
644-
metadata.signed,
641+
f"Failed to verify {self.keyid} signature"
645642
)
646643
except (
647644
sslib_exceptions.CryptoError,
648645
sslib_exceptions.FormatError,
649646
sslib_exceptions.UnsupportedAlgorithmError,
650647
) as e:
651648
raise exceptions.UnsignedMetadataError(
652-
f"Failed to verify {self.keyid} signature",
653-
metadata.signed,
649+
f"Failed to verify {self.keyid} signature"
654650
) from e
655651

656652

@@ -1323,8 +1319,8 @@ def from_file(
13231319
specified the securesystemslib default hash algorithm is used.
13241320
Raises:
13251321
FileNotFoundError: The file doesn't exist.
1326-
UnsupportedAlgorithmError: The hash algorithms list
1327-
contains an unsupported algorithm.
1322+
ValueError: The hash algorithms list contains an unsupported
1323+
algorithm.
13281324
"""
13291325
with open(local_path, "rb") as file:
13301326
return cls.from_data(target_file_path, file, hash_algorithms)
@@ -1346,8 +1342,8 @@ def from_data(
13461342
specified the securesystemslib default hash algorithm is used.
13471343
13481344
Raises:
1349-
UnsupportedAlgorithmError: The hash algorithms list
1350-
contains an unsupported algorithm.
1345+
ValueError: The hash algorithms list contains an unsupported
1346+
algorithm.
13511347
"""
13521348
if isinstance(data, bytes):
13531349
length = len(data)
@@ -1373,9 +1369,7 @@ def from_data(
13731369
sslib_exceptions.UnsupportedAlgorithmError,
13741370
sslib_exceptions.FormatError,
13751371
) as e:
1376-
raise exceptions.UnsupportedAlgorithmError(
1377-
f"Unsupported algorithm '{algorithm}'"
1378-
) from e
1372+
raise ValueError(f"Unsupported algorithm '{algorithm}'") from e
13791373

13801374
hashes[algorithm] = digest_object.hexdigest()
13811375

0 commit comments

Comments
 (0)