Skip to content

Commit

Permalink
Merge 1a4d870 into 8f95162
Browse files Browse the repository at this point in the history
  • Loading branch information
NicholasTanz committed Feb 20, 2024
2 parents 8f95162 + 1a4d870 commit 46b71ab
Show file tree
Hide file tree
Showing 13 changed files with 98 additions and 65 deletions.
4 changes: 1 addition & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ updates:
# Python dependencies that are only pinned to ensure test reproducibility
patterns:
- "bandit"
- "black"
- "coverage"
- "isort"
- "mypy"
- "pydocstyle"
- "pylint"
- "ruff"
- "tox"
dependencies:
# Python (developer) runtime dependencies. Also any new dependencies not
Expand Down
4 changes: 3 additions & 1 deletion examples/repository/_simplerepo.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ def _get_verification_result(
)

def open(self, role: str) -> Metadata:
"""Return current Metadata for role from 'storage' (or create a new one)"""
"""Return current Metadata for role from 'storage'
(or create a new one)
"""

if role not in self.role_cache:
signed_init = _signed_init.get(role, Targets)
Expand Down
32 changes: 19 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,27 @@ include = [
# from `tests` so the root directory must be added to Python's path for editable installations
dev-mode-dirs = ["."]

# Black section
# Read more here: https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file
[tool.black]
# Ruff section
# Read more here: https://docs.astral.sh/ruff/linter/#rule-selection
[tool.ruff]
line-length=80

# Isort section
# Read more here: https://pycqa.github.io/isort/docs/configuration/config_files.html
[tool.isort]
profile="black"
line_length=80
known_first_party = ["tuf"]
[tool.ruff.lint]
select = [
"D", # pydocstyle
"I", # isort
"F", # pyflakes
"N", # pep8-naming
"E" # pycodestyle
]
ignore = ["D400","D415","D213","D205","D202","D107","D407","D413","D212","D104","D406","D105","D411","D401","D200","D203"]
[tool.ruff.lint.per-file-ignores]
"tests/*" = ["D", "E"]
"examples/*/*" = ["D"]
"tuf/repository/__init__.py" = ["F401"]
"tuf/api/exceptions.py" = ["F401"]
"tuf/repository/_repository.py" = ["N818"]
"verify_release" = ["F401", "D103", "E501"]

# Pylint section

Expand Down Expand Up @@ -156,7 +166,3 @@ module = [
"securesystemslib.*",
]
ignore_missing_imports = "True"

[tool.pydocstyle]
inherit = false
ignore = "D400,D415,D213,D205,D202,D107,D407,D413,D212,D104,D406,D105,D411,D401,D200,D203"
4 changes: 1 addition & 3 deletions requirements/lint.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
# Lint tools
# (We are not so interested in the specific versions of the tools: the versions
# are pinned to prevent unexpected linting failures when tools update)
black==24.2.0
isort==5.13.2
pylint==3.0.3
ruff==0.2.1
mypy==1.8.0
bandit==1.7.7
pydocstyle==6.3.0
6 changes: 3 additions & 3 deletions tests/test_updater_top_level_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,9 +555,9 @@ def test_new_targets_hash_mismatch(self) -> None:
# Modify targets contents without updating
# snapshot's targets hashes
self.sim.targets.version += 1
self.sim.snapshot.meta["targets.json"].version = (
self.sim.targets.version
)
self.sim.snapshot.meta[
"targets.json"
].version = self.sim.targets.version
self.sim.snapshot.version += 1
self.sim.update_timestamp()

Expand Down
2 changes: 1 addition & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def run_sub_tests_with_dataset(
cases in dataset"""

def real_decorator(
function: Callable[[unittest.TestCase, Any], None]
function: Callable[[unittest.TestCase, Any], None],
) -> Callable[[unittest.TestCase], None]:
def wrapper(test_cls: unittest.TestCase) -> None:
for case, data in dataset.items():
Expand Down
6 changes: 2 additions & 4 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,14 @@ deps =
--editable {toxinidir}
lint_dirs = tuf examples tests verify_release
commands =
black --check --diff {[testenv:lint]lint_dirs}
isort --check --diff {[testenv:lint]lint_dirs}
ruff check {[testenv:lint]lint_dirs}
ruff format --diff {[testenv:lint]lint_dirs}
pylint -j 0 --rcfile=pyproject.toml {[testenv:lint]lint_dirs}

mypy {[testenv:lint]lint_dirs}

bandit -r tuf

pydocstyle tuf

[testenv:docs]
deps =
-r{toxinidir}/requirements/docs.txt
Expand Down
5 changes: 4 additions & 1 deletion tuf/api/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#### Repository errors ####

# pylint: disable=unused-import
# ruff: disable unused-inport
from securesystemslib.exceptions import StorageError


Expand All @@ -23,7 +24,9 @@ class RepositoryError(Exception):


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


class BadVersionNumberError(RepositoryError):
Expand Down
81 changes: 51 additions & 30 deletions tuf/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
The above principle means that a ``Metadata`` object represents a single
metadata file, and has a ``signed`` attribute that is an instance of one of the
four top level signed classes (``Root``, ``Timestamp``, ``Snapshot`` and ``Targets``).
To make Python type annotations useful ``Metadata`` can be type constrained: e.g. the
signed attribute of ``Metadata[Root]`` is known to be ``Root``.
four top level signed classes (``Root``, ``Timestamp``, ``Snapshot`` and
``Targets``). To make Python type annotations useful ``Metadata`` can be
type constrained: e.g. the signed attribute of ``Metadata[Root]``
is known to be ``Root``.
Currently Metadata API supports JSON as the file format.
Expand Down Expand Up @@ -101,8 +102,8 @@ class Metadata(Generic[T]):
Using a type constraint is not required but not doing so means T is not a
specific type so static typing cannot happen. Note that the type constraint
``[Root]`` is not validated at runtime (as pure annotations are not available
then).
``[Root]`` is not validated at runtime (as pure annotations are not
available then).
New Metadata instances can be created from scratch with::
Expand Down Expand Up @@ -227,6 +228,7 @@ def from_file(
storage_backend: Object that implements
``securesystemslib.storage.StorageBackendInterface``.
Default is ``FilesystemBackend`` (i.e. a local file).
Raises:
StorageError: The file cannot be read.
tuf.api.serialization.DeserializationError:
Expand Down Expand Up @@ -357,9 +359,10 @@ def sign(
"""Create signature over ``signed`` and assigns it to ``signatures``.
Args:
signer: A ``securesystemslib.signer.Signer`` object that provides a private
key and signing implementation to generate the signature. A standard
implementation is available in ``securesystemslib.signer.SSlibSigner``.
signer: A ``securesystemslib.signer.Signer`` object that provides a
private key and signing implementation to generate the signature. A
standard implementation is available in
``securesystemslib.signer.SSlibSigner``.
append: ``True`` if the signature should be appended to
the list of signatures or replace any existing signatures. The
default behavior is to replace signatures.
Expand Down Expand Up @@ -403,7 +406,8 @@ def verify_delegate(
threshold of keys for ``delegated_role``.
.. deprecated:: 3.1.0
Please use ``Root.verify_delegate()`` or ``Targets.verify_delegate()``.
Please use ``Root.verify_delegate()`` or
``Targets.verify_delegate()``.
"""

if self.signed.type not in ["root", "targets"]:
Expand Down Expand Up @@ -522,7 +526,9 @@ def to_dict(self) -> Dict[str, Any]:
@classmethod
@abc.abstractmethod
def from_dict(cls, signed_dict: Dict[str, Any]) -> "Signed":
"""Deserialization helper, creates object from json/dict representation."""
"""Deserialization helper, creates object from json/dict
representation.
"""
raise NotImplementedError

@classmethod
Expand All @@ -533,7 +539,8 @@ def _common_fields_from_dict(
representation, and returns an ordered list to be passed as leading
positional arguments to a subclass constructor.
See ``{Root, Timestamp, Snapshot, Targets}.from_dict`` methods for usage.
See ``{Root, Timestamp, Snapshot, Targets}.from_dict``
methods for usage.
"""
_type = signed_dict.pop("_type")
Expand All @@ -551,7 +558,8 @@ def _common_fields_from_dict(
return version, spec_version, expires

def _common_fields_to_dict(self) -> Dict[str, Any]:
"""Return a dict representation of common fields of ``Signed`` instances.
"""Return a dict representation of common fields of
``Signed`` instances.
See ``{Root, Timestamp, Snapshot, Targets}.to_dict`` methods for usage.
Expand Down Expand Up @@ -700,19 +708,27 @@ def __bool__(self) -> bool:

@property
def verified(self) -> bool:
"""True if threshold of signatures is met in both underlying VerificationResults."""
"""True if threshold of signatures is met in both underlying
VerificationResults.
"""
return self.first.verified and self.second.verified

@property
def signed(self) -> Dict[str, Key]:
"""Dictionary of all signing keys that have signed, from both VerificationResults"""
# return a union of all signed (in python<3.9 this requires dict unpacking)
"""Dictionary of all signing keys that have signed, from both
VerificationResults.
return a union of all signed (in python<3.9 this requires
dict unpacking)
"""
return {**self.first.signed, **self.second.signed}

@property
def unsigned(self) -> Dict[str, Key]:
"""Dictionary of all signing keys that have not signed, from both VerificationResults"""
# return a union of all unsigned (in python<3.9 this requires dict unpacking)
"""Dictionary of all signing keys that have not signed, from both
VerificationResults.
return a union of all unsigned (in python<3.9 this requires
dict unpacking)
"""
return {**self.first.unsigned, **self.second.unsigned}


Expand Down Expand Up @@ -828,8 +844,8 @@ class Root(Signed, _DelegatorMixin):
roles: Dictionary of role names to Roles. Defines which keys are
required to sign the metadata for a specific role. Default is
a dictionary of top level roles without keys and threshold of 1.
consistent_snapshot: ``True`` if repository supports consistent snapshots.
Default is True.
consistent_snapshot: ``True`` if repository supports consistent
snapshots. Default is True.
unrecognized_fields: Dictionary of all attributes that are not managed
by TUF Metadata API
Expand Down Expand Up @@ -1191,6 +1207,7 @@ def from_data(
data: Metadata bytes that the metafile represents.
hash_algorithms: Hash algorithms to create the hashes with. If not
specified, the securesystemslib default hash algorithm is used.
Raises:
ValueError: The hash algorithms list contains an unsupported
algorithm.
Expand Down Expand Up @@ -1234,7 +1251,8 @@ class Timestamp(Signed):
"""A container for the signed part of timestamp metadata.
TUF file format uses a dictionary to contain the snapshot information:
this is not the case with ``Timestamp.snapshot_meta`` which is a ``MetaFile``.
this is not the case with ``Timestamp.snapshot_meta`` which is a
``MetaFile``.
*All parameters named below are not just constructor arguments but also
instance attributes.*
Expand Down Expand Up @@ -1366,12 +1384,13 @@ class DelegatedRole(Role):
A delegation can happen in two ways:
- ``paths`` is set: delegates targets matching any path pattern in ``paths``
- ``path_hash_prefixes`` is set: delegates targets whose target path hash
starts with any of the prefixes in ``path_hash_prefixes``
- ``paths`` is set: delegates targets matching any path pattern in
``paths``
- ``path_hash_prefixes`` is set: delegates targets whose target path
hash starts with any of the prefixes in ``path_hash_prefixes``
``paths`` and ``path_hash_prefixes`` are mutually exclusive: both cannot be
set, at least one of them must be set.
``paths`` and ``path_hash_prefixes`` are mutually exclusive:
both cannot be set, at least one of them must be set.
*All parameters named below are not just constructor arguments but also
instance attributes.*
Expand Down Expand Up @@ -1491,10 +1510,10 @@ def is_delegated_path(self, target_filepath: str) -> bool:
"""Determine whether the given ``target_filepath`` is in one of
the paths that ``DelegatedRole`` is trusted to provide.
The ``target_filepath`` and the ``DelegatedRole`` paths are expected to be
in their canonical forms, so e.g. "a/b" instead of "a//b" . Only "/" is
supported as target path separator. Leading separators are not handled
as special cases (see `TUF specification on targetpath
The ``target_filepath`` and the ``DelegatedRole`` paths are expected to
be in their canonical forms, so e.g. "a/b" instead of "a//b" . Only "/"
is supported as target path separator. Leading separators are not
handled as special cases (see `TUF specification on targetpath
<https://theupdateframework.github.io/specification/latest/#targetpath>`_).
Args:
Expand Down Expand Up @@ -1613,7 +1632,8 @@ def to_dict(self) -> Dict[str, Any]:
}

def get_role_for_target(self, target_filepath: str) -> str:
"""Calculate the name of the delegated role responsible for ``target_filepath``.
"""Calculate the name of the delegated role responsible for
``target_filepath``.
The target at path ``target_filepath`` is assigned to a bin by casting
the left-most ``bit_length`` of bits of the file path hash digest to
Expand Down Expand Up @@ -1897,6 +1917,7 @@ def from_file(
local_path: Local path to target file content.
hash_algorithms: Hash algorithms to calculate hashes with. If not
specified the securesystemslib default hash algorithm is used.
Raises:
FileNotFoundError: The file doesn't exist.
ValueError: The hash algorithms list contains an unsupported
Expand Down
6 changes: 4 additions & 2 deletions tuf/ngclient/_internal/requests_fetcher.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Copyright 2021, New York University and the TUF contributors
# SPDX-License-Identifier: MIT OR Apache-2.0

"""Provides an implementation of ``FetcherInterface`` using the Requests HTTP library.
"""Provides an implementation of ``FetcherInterface`` using the Requests HTTP
library.
"""

# requests_fetcher is public but comes from _internal for now (because
Expand Down Expand Up @@ -117,7 +118,8 @@ def _chunks(self, response: "requests.Response") -> Iterator[bytes]:
response.close()

def _get_session(self, url: str) -> requests.Session:
"""Return a different customized requests.Session per schema+hostname combination.
"""Return a different customized requests.Session per schema+hostname
combination.
Raises:
exceptions.DownloadError: When there is a problem parsing the url.
Expand Down
11 changes: 7 additions & 4 deletions tuf/ngclient/_internal/trusted_metadata_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@
class TrustedMetadataSet(abc.Mapping):
"""Internal class to keep track of trusted metadata in ``Updater``.
``TrustedMetadataSet`` ensures that the collection of metadata in it is valid
and trusted through the whole client update workflow. It provides easy ways
to update the metadata with the caller making decisions on what is updated.
``TrustedMetadataSet`` ensures that the collection of metadata in it is
valid and trusted through the whole client update workflow. It provides
easy ways to update the metadata with the caller making decisions on
what is updated.
"""

def __init__(self, root_data: bytes):
Expand Down Expand Up @@ -107,7 +108,9 @@ def __len__(self) -> int:
return len(self._trusted_set)

def __iter__(self) -> Iterator[Metadata]:
"""Return iterator over ``Metadata`` objects in ``TrustedMetadataSet``."""
"""Return iterator over ``Metadata`` objects in
``TrustedMetadataSet``.
"""
return iter(self._trusted_set.values())

# Helper properties for top level metadata
Expand Down
1 change: 1 addition & 0 deletions tuf/repository/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
The repository module is not considered part of the stable python-tuf API yet.
"""

# ruff: disable unused-inport
from tuf.repository._repository import AbortEdit, Repository

0 comments on commit 46b71ab

Please sign in to comment.