Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/manual_repo/basic_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

"""

from __future__ import annotations

import os
import tempfile
from datetime import datetime, timedelta, timezone
Expand Down
7 changes: 6 additions & 1 deletion examples/manual_repo/hashed_bin_delegation.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

"""

from __future__ import annotations

import hashlib
import os
import tempfile
from collections.abc import Iterator
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import TYPE_CHECKING

from securesystemslib.signer import CryptoSigner, Signer

Expand All @@ -34,6 +36,9 @@
)
from tuf.api.serialization.json import JSONSerializer

if TYPE_CHECKING:
from collections.abc import Iterator


def _in(days: float) -> datetime:
"""Adds 'days' to now and returns datetime object w/o microseconds."""
Expand Down
2 changes: 2 additions & 0 deletions examples/manual_repo/succinct_hash_bin_delegations.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
NOTE: Metadata files will be written to a 'tmp*'-directory in CWD.
"""

from __future__ import annotations

import math
import os
import tempfile
Expand Down
5 changes: 3 additions & 2 deletions examples/repository/_simplerepo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

"""Simple example of using the repository library to build a repository"""

from __future__ import annotations

import copy
import json
import logging
from collections import defaultdict
from datetime import datetime, timedelta, timezone
from typing import Union

from securesystemslib.signer import CryptoSigner, Key, Signer

Expand Down Expand Up @@ -93,7 +94,7 @@ def snapshot_info(self) -> MetaFile:

def _get_verification_result(
self, role: str, md: Metadata
) -> Union[VerificationResult, RootVerificationResult]:
) -> VerificationResult | RootVerificationResult:
"""Verify roles metadata using the existing repository metadata"""
if role == Root.type:
assert isinstance(md.signed, Root)
Expand Down
2 changes: 2 additions & 0 deletions examples/uploader/_localrepo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

"""A Repository implementation for maintainer and developer tools"""

from __future__ import annotations

import contextlib
import copy
import json
Expand Down
13 changes: 11 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ name = "tuf"
description = "A secure updater framework for Python"
readme = "README.md"
license = { text = "MIT OR Apache-2.0" }
requires-python = ">=3.9"
requires-python = ">=3.8"
authors = [
{ email = "[email protected]" },
]
Expand Down Expand Up @@ -96,7 +96,6 @@ ignore = [
"TRY",

# Individual rules that have been disabled
"ANN101", "ANN102", # nonsense, deprecated in ruff
"D400", "D415", "D213", "D205", "D202", "D107", "D407", "D413", "D212", "D104", "D406", "D105", "D411", "D401", "D200", "D203",
"ISC001", # incompatible with ruff formatter
"PLR0913", "PLR2004",
Expand Down Expand Up @@ -150,3 +149,13 @@ module = [
"securesystemslib.*",
]
ignore_missing_imports = "True"

[tool.coverage.report]
exclude_also = [
# abstract class method definition
"raise NotImplementedError",
# defensive programming: these cannot happen
"raise AssertionError",
# imports for mypy only
"if TYPE_CHECKING",
]
2 changes: 1 addition & 1 deletion requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
-r pinned.txt

# coverage measurement
coverage==7.6.8
coverage[toml]==7.6.8
freezegun==1.5.1
5 changes: 3 additions & 2 deletions tests/generated_data/generate_md.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
# Copyright New York University and the TUF contributors
# SPDX-License-Identifier: MIT OR Apache-2.0

from __future__ import annotations

import os
import sys
from datetime import datetime, timezone
from typing import Optional

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from securesystemslib.signer import CryptoSigner, Signer, SSlibKey
Expand Down Expand Up @@ -80,7 +81,7 @@ def verify_generation(md: Metadata, path: str) -> None:


def generate_all_files(
dump: Optional[bool] = False, verify: Optional[bool] = False
dump: bool | None = False, verify: bool | None = False
) -> None:
"""Generate a new repository and optionally verify it.

Expand Down
26 changes: 14 additions & 12 deletions tests/repository_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@
updater.refresh()
"""

from __future__ import annotations

import datetime
import logging
import os
import tempfile
from collections.abc import Iterator
from dataclasses import dataclass, field
from typing import Optional
from typing import TYPE_CHECKING
from urllib import parse

import securesystemslib.hash as sslib_hash
Expand All @@ -72,6 +73,9 @@
from tuf.api.serialization.json import JSONSerializer
from tuf.ngclient.fetcher import FetcherInterface

if TYPE_CHECKING:
from collections.abc import Iterator

logger = logging.getLogger(__name__)

SPEC_VER = ".".join(SPECIFICATION_VERSION)
Expand All @@ -81,8 +85,8 @@
class FetchTracker:
"""Fetcher counter for metadata and targets."""

metadata: list[tuple[str, Optional[int]]] = field(default_factory=list)
targets: list[tuple[str, Optional[str]]] = field(default_factory=list)
metadata: list[tuple[str, int | None]] = field(default_factory=list)
targets: list[tuple[str, str | None]] = field(default_factory=list)


@dataclass
Expand Down Expand Up @@ -116,7 +120,7 @@ def __init__(self) -> None:
# Enable hash-prefixed target file names
self.prefix_targets_with_hash = True

self.dump_dir: Optional[str] = None
self.dump_dir: str | None = None
self.dump_version = 0

self.fetch_tracker = FetchTracker()
Expand Down Expand Up @@ -201,7 +205,7 @@ def _fetch(self, url: str) -> Iterator[bytes]:
if role == Root.type or (
self.root.consistent_snapshot and ver_and_name != Timestamp.type
):
version: Optional[int] = int(version_str)
version: int | None = int(version_str)
else:
# the file is not version-prefixed
role = ver_and_name
Expand All @@ -213,7 +217,7 @@ def _fetch(self, url: str) -> Iterator[bytes]:
target_path = path[len("/targets/") :]
dir_parts, sep, prefixed_filename = target_path.rpartition("/")
# extract the hash prefix, if any
prefix: Optional[str] = None
prefix: str | None = None
filename = prefixed_filename
if self.root.consistent_snapshot and self.prefix_targets_with_hash:
prefix, _, filename = prefixed_filename.partition(".")
Expand All @@ -223,9 +227,7 @@ def _fetch(self, url: str) -> Iterator[bytes]:
else:
raise DownloadHTTPError(f"Unknown path '{path}'", 404)

def fetch_target(
self, target_path: str, target_hash: Optional[str]
) -> bytes:
def fetch_target(self, target_path: str, target_hash: str | None) -> bytes:
"""Return data for 'target_path', checking 'target_hash' if it is given.

If hash is None, then consistent_snapshot is not used.
Expand All @@ -244,7 +246,7 @@ def fetch_target(
logger.debug("fetched target %s", target_path)
return repo_target.data

def fetch_metadata(self, role: str, version: Optional[int] = None) -> bytes:
def fetch_metadata(self, role: str, version: int | None = None) -> bytes:
"""Return signed metadata for 'role', using 'version' if it is given.

If version is None, non-versioned metadata is being requested.
Expand All @@ -261,7 +263,7 @@ def fetch_metadata(self, role: str, version: Optional[int] = None) -> bytes:
return self.signed_roots[version - 1]

# sign and serialize the requested metadata
md: Optional[Metadata]
md: Metadata | None
if role == Timestamp.type:
md = self.md_timestamp
elif role == Snapshot.type:
Expand Down
8 changes: 5 additions & 3 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# SPDX-License-Identifier: MIT OR Apache-2.0
"""Unit tests for api/metadata.py"""

from __future__ import annotations

import json
import logging
import os
Expand All @@ -12,7 +14,7 @@
from copy import copy, deepcopy
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import ClassVar, Optional
from typing import ClassVar

from securesystemslib import exceptions as sslib_exceptions
from securesystemslib import hash as sslib_hash
Expand Down Expand Up @@ -245,8 +247,8 @@ def from_priv_key_uri(
cls,
priv_key_uri: str,
public_key: Key,
secrets_handler: Optional[SecretsHandler] = None,
) -> "Signer":
secrets_handler: SecretsHandler | None = None,
) -> Signer:
pass

@property
Expand Down
2 changes: 2 additions & 0 deletions tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# SPDX-License-Identifier: MIT OR Apache-2.0
"""Unit tests for 'examples' scripts."""

from __future__ import annotations

import glob
import os
import shutil
Expand Down
4 changes: 3 additions & 1 deletion tests/test_metadata_eq_.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

"""Test __eq__ implementations of classes inside tuf/api/metadata.py."""

from __future__ import annotations

import copy
import os
import sys
Expand Down Expand Up @@ -63,7 +65,7 @@ def setUpClass(cls) -> None:

# Keys are class names.
# Values are dictionaries containing attribute names and their new values.
classes_attributes_modifications: utils.DataSet = {
classes_attributes_modifications = {
"Metadata": {"signed": None, "signatures": None},
"Signed": {"version": -1, "spec_version": "0.0.0"},
"Key": {"keyid": "a", "keytype": "foo", "scheme": "b", "keyval": "b"},
Expand Down
Loading