From e3861dd4696c33d03b35ce1c4ebb80cf7ca23c3c Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Mon, 3 Feb 2025 12:45:32 +0200 Subject: [PATCH 1/3] Stricter mypy setup * Move config to pyproject.toml * Turn on useful mypy options * Don't check tests with mypy: too much to fix right now * Add py.typed to announce this project is type annotated * Fix various annotation issues Issues remain in hash module Signed-off-by: Jussi Kukkonen --- mypy.ini | 37 ------------------------ pyproject.toml | 40 ++++++++++++++++++++++++-- securesystemslib/py.typed | 0 securesystemslib/signer/_hsm_signer.py | 2 +- securesystemslib/signer/_key.py | 7 +++-- securesystemslib/signer/_utils.py | 2 +- securesystemslib/storage.py | 4 +-- tox.ini | 2 +- 8 files changed, 48 insertions(+), 46 deletions(-) delete mode 100644 mypy.ini create mode 100644 securesystemslib/py.typed diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 09dcde40..00000000 --- a/mypy.ini +++ /dev/null @@ -1,37 +0,0 @@ -[mypy] -warn_unused_configs = True - -exclude = securesystemslib/_vendor - -# Supress error messages until enough modules -# are type annotated -follow_imports = silent - -# let's not install typeshed annotations for GCPSigner -[mypy-google.*] -ignore_missing_imports = True - -# Suppress error messages for non-annotating dependencies -[mypy-PyKCS11.*] -ignore_missing_imports = True - -[mypy-asn1crypto.*] -ignore_missing_imports = True - -[mypy-sigstore_protobuf_specs.*] -ignore_missing_imports = True - -[mypy-pyspx.*] -ignore_missing_imports = True - -[mypy-azure.*] -ignore_missing_imports = True - -[mypy-boto3.*] -ignore_missing_imports = True - -[mypy-botocore.*] -ignore_missing_imports = True - -[mypy-hvac.*] -ignore_missing_imports = True diff --git a/pyproject.toml b/pyproject.toml index 9399f246..de430c18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,7 +62,6 @@ include = [ "/securesystemslib", "/requirements*.txt", "/tox.ini", - "/mypy.ini", "/CHANGELOG.md", "/.coveragerc", ] @@ -87,4 +86,41 @@ indent-width = 4 "tests/*" = [ "S", # bandit: Not running bandit on tests "E501" # line-too-long -] \ No newline at end of file +] + +[tool.mypy] +warn_unused_configs = "True" +warn_redundant_casts = "True" +warn_unused_ignores = "True" +warn_unreachable = "True" +strict_equality = "True" +disallow_untyped_defs = "True" +show_error_codes = "True" + +exclude = [ + "^securesystemslib/_vendor/", + "^securesystemslib/_gpg/" +] + +[[tool.mypy.overrides]] +module = [ + # let's not install typeshed annotations for GCPSigner + "google.*", + # Suppress error messages for non-annotating dependencies + "PyKCS11.*", + "asn1crypto.*", + "sigstore_protobuf_specs.*", + "pyspx.*", + "azure.*", + "boto3.*", + "botocore.*", + "hvac.*", +] +ignore_missing_imports = "True" + +[[tool.mypy.overrides]] +module = [ + "securesystemslib._gpg.*", + "securesystemslib._vendor.*", +] +follow_imports = "skip" diff --git a/securesystemslib/py.typed b/securesystemslib/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/securesystemslib/signer/_hsm_signer.py b/securesystemslib/signer/_hsm_signer.py index 1d830370..3f79125b 100644 --- a/securesystemslib/signer/_hsm_signer.py +++ b/securesystemslib/signer/_hsm_signer.py @@ -64,7 +64,7 @@ _PYKCS11LIB = None -def PYKCS11LIB(): # noqa: N802 +def PYKCS11LIB(): # type: ignore[no-untyped-def] # noqa: N802 """Pseudo-singleton to load shared library using PYKCS11LIB envvar only once.""" global _PYKCS11LIB # noqa: PLW0603 if _PYKCS11LIB is None: diff --git a/securesystemslib/signer/_key.py b/securesystemslib/signer/_key.py index 131dce5b..25f2434f 100644 --- a/securesystemslib/signer/_key.py +++ b/securesystemslib/signer/_key.py @@ -26,6 +26,7 @@ SECP256R1, SECP384R1, SECP521R1, + EllipticCurve, EllipticCurvePublicKey, ) from cryptography.hazmat.primitives.asymmetric.ed25519 import ( @@ -346,11 +347,13 @@ def _verify_ed25519_fallback(self, signature: bytes, data: bytes) -> None: def _verify(self, signature: bytes, data: bytes) -> None: """Helper to verify signature using pyca/cryptography (default).""" - def _validate_type(key, type_): + def _validate_type(key: object, type_: type) -> None: if not isinstance(key, type_): raise ValueError(f"bad key {key} for {self.scheme}") - def _validate_curve(key, curve): + def _validate_curve( + key: EllipticCurvePublicKey, curve: type[EllipticCurve] + ) -> None: if not isinstance(key.curve, curve): raise ValueError(f"bad curve {key.curve} for {self.scheme}") diff --git a/securesystemslib/signer/_utils.py b/securesystemslib/signer/_utils.py index 4a364f96..c9bfae1b 100644 --- a/securesystemslib/signer/_utils.py +++ b/securesystemslib/signer/_utils.py @@ -9,7 +9,7 @@ from securesystemslib.hash import digest -def compute_default_keyid(keytype: str, scheme, keyval: dict[str, Any]) -> str: +def compute_default_keyid(keytype: str, scheme: str, keyval: dict[str, Any]) -> str: """Return sha256 hexdigest of the canonical json of the key.""" data: str | None = encode_canonical( { diff --git a/securesystemslib/storage.py b/securesystemslib/storage.py index c67535ac..3f6d4d4b 100644 --- a/securesystemslib/storage.py +++ b/securesystemslib/storage.py @@ -25,7 +25,7 @@ from abc import ABCMeta, abstractmethod from collections.abc import Iterator from contextlib import contextmanager -from typing import IO, BinaryIO +from typing import IO, Any, BinaryIO from securesystemslib import exceptions @@ -189,7 +189,7 @@ class FilesystemBackend(StorageBackendInterface): # objects. _instance = None - def __new__(cls, *args, **kwargs): + def __new__(cls, *args: Any, **kwargs: Any) -> FilesystemBackend: if cls._instance is None: cls._instance = object.__new__(cls, *args, **kwargs) return cls._instance diff --git a/tox.ini b/tox.ini index 5cfe70c7..cce94c52 100644 --- a/tox.ini +++ b/tox.ini @@ -69,7 +69,7 @@ commands = ruff format --diff {[testenv:lint]lint_dirs} ruff check {[testenv:lint]lint_dirs} - mypy {[testenv:lint]lint_dirs} + mypy securesystemslib zizmor --persona=pedantic -q . [testenv:fix] From 2883df933b73c5a7bf94ed656d7cc62aaa464f73 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Mon, 17 Mar 2025 10:52:05 +0200 Subject: [PATCH 2/3] workflows: Run linter on oldest supported Python This is useful since it will notice use of too new features (or lack of "from __future__ import annotations"). Signed-off-by: Jussi Kukkonen --- .github/workflows/_test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 98767fd2..58c6ddc1 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -16,6 +16,7 @@ jobs: include: # Run macOS tests on 3.9 (current OS X python) and latest, # Run Windows and "special" tests on latest Python version only + # Run linter on oldest supported Python - python-version: "3.9" os: macos-latest toxenv: py @@ -34,7 +35,7 @@ jobs: - python-version: "3.13" os: ubuntu-latest toxenv: py-test-gpg-fails - - python-version: "3.13" + - python-version: "3.9" os: ubuntu-latest toxenv: lint From d17acca69c9f679431aad80edc4438bdf2e5f2fd Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Wed, 19 Mar 2025 13:57:06 +0200 Subject: [PATCH 3/3] lint: Exclude hash module from linting Plan is to deprecate hash soon. Signed-off-by: Jussi Kukkonen --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index de430c18..3a349a91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,7 +99,8 @@ show_error_codes = "True" exclude = [ "^securesystemslib/_vendor/", - "^securesystemslib/_gpg/" + "^securesystemslib/_gpg/", + "^securesystemslib/hash.py", ] [[tool.mypy.overrides]] @@ -122,5 +123,6 @@ ignore_missing_imports = "True" module = [ "securesystemslib._gpg.*", "securesystemslib._vendor.*", + "securesystemslib.hash", ] follow_imports = "skip"