Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-service_identity for
openSUSE:Factory checked in at 2024-11-01 21:00:44
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-service_identity (Old)
and /work/SRC/openSUSE:Factory/.python-service_identity.new.2020 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-service_identity"
Fri Nov 1 21:00:44 2024 rev:16 rq:1219726 version:24.2.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-service_identity/python-service_identity.changes
2024-01-21 23:07:26.671511362 +0100
+++
/work/SRC/openSUSE:Factory/.python-service_identity.new.2020/python-service_identity.changes
2024-11-01 21:00:48.745507595 +0100
@@ -1,0 +2,11 @@
+Wed Oct 30 19:54:23 UTC 2024 - Dirk Müller <[email protected]>
+
+- update to 24.2.0:
+ * Python 3.13 is now officially supported.
+ * pyOpenSSL's identity extraction has been reimplemented using
+ *cryptography*'s primitives instead of deprecated pyOpenSSL
+ APIs.
+ * As a result, the oldest supported pyOpenSSL version is now
+ 17.1.0.
+
+-------------------------------------------------------------------
Old:
----
24.1.0.tar.gz
New:
----
24.2.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-service_identity.spec ++++++
--- /var/tmp/diff_new_pack.89EqKV/_old 2024-11-01 21:00:49.505539320 +0100
+++ /var/tmp/diff_new_pack.89EqKV/_new 2024-11-01 21:00:49.509539487 +0100
@@ -19,7 +19,7 @@
%define oname service_identity
%{?sle15_python_module_pythons}
Name: python-service_identity
-Version: 24.1.0
+Version: 24.2.0
Release: 0
Summary: Service identity verification for pyOpenSSL
License: MIT
@@ -34,7 +34,7 @@
BuildRequires: %{python_module hatchling >= 1.14.0}
BuildRequires: %{python_module idna}
BuildRequires: %{python_module pip}
-BuildRequires: %{python_module pyOpenSSL >= 17.0.0}
+BuildRequires: %{python_module pyOpenSSL >= 17.1.0}
BuildRequires: %{python_module pyasn1-modules}
BuildRequires: %{python_module pyasn1}
BuildRequires: %{python_module pytest}
@@ -46,7 +46,7 @@
Requires: python-pyasn1
Requires: python-pyasn1-modules
Recommends: python-idna
-Recommends: python-pyOpenSSL
+Recommends: python-pyOpenSSL >= 17.1.0
BuildArch: noarch
%ifpython2
Requires: python-ipaddress
++++++ 24.1.0.tar.gz -> 24.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/.git_archival.txt
new/service-identity-24.2.0/.git_archival.txt
--- old/service-identity-24.1.0/.git_archival.txt 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/.git_archival.txt 2024-10-26
09:10:38.000000000 +0200
@@ -1,4 +1,3 @@
-node: e5ba15ec13b1750cae35004dede2e6e4af74308f
-node-date: 2024-01-14T08:05:19+01:00
-describe-name: 24.1.0
-ref-names: tag: 24.1.0
+node: b51873e5aff777ff2e35dfb2bee1f4acbf203b25
+node-date: 2024-10-26T09:10:38+02:00
+describe-name: 24.2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/.github/CONTRIBUTING.md
new/service-identity-24.2.0/.github/CONTRIBUTING.md
--- old/service-identity-24.1.0/.github/CONTRIBUTING.md 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/.github/CONTRIBUTING.md 2024-10-26
09:10:38.000000000 +0200
@@ -137,8 +137,10 @@
A very important return value.
"""
```
+
- If you add or change public APIs, tag the docstring using `..
versionadded:: 16.0.0 WHAT` or `.. versionchanged:: 16.2.0 WHAT`.
-- We use [Ruff](https://ruff.rs/) to sort our imports, and we use
[Black](https://github.com/psf/black) with line length of 79 characters to
format our code.
+
+- We follow [PEP 8](https://peps.python.org/pep-0008/) as enforced by
[Ruff](https://ruff.rs/) with a line length of 79 characters.
As long as you run our full [*tox*] suite before committing, or install our
[*pre-commit*] hooks (ideally you'll do both â see [*Local Development
Environment*](#local-development-environment) above), you won't have to spend
any time on formatting your code at all.
If you don't, [CI] will catch it for you â but that seems like a waste of
your time!
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/.github/SECURITY.md
new/service-identity-24.2.0/.github/SECURITY.md
--- old/service-identity-24.1.0/.github/SECURITY.md 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/.github/SECURITY.md 2024-10-26
09:10:38.000000000 +0200
@@ -2,7 +2,7 @@
## Supported Versions
-We are following [*CalVer*](https://calver.org) with generous
backwards-compatibility guarantees.
+We are following [Calendar Versioning](https://calver.org) with generous
backwards-compatibility guarantees.
*Therefore we only support the latest version*.
That said, you shouldn't be afraid to upgrade if you're only using our
documented public APIs and pay attention to `DeprecationWarning`s.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/.github/workflows/ci.yml
new/service-identity-24.2.0/.github/workflows/ci.yml
--- old/service-identity-24.1.0/.github/workflows/ci.yml 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/.github/workflows/ci.yml 2024-10-26
09:10:38.000000000 +0200
@@ -4,6 +4,7 @@
on:
push:
branches: [main]
+ tags: ["*"]
pull_request:
workflow_dispatch:
@@ -14,6 +15,7 @@
permissions: {}
+
jobs:
lint:
name: Run linters
@@ -22,61 +24,81 @@
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
- python-version: "3.11" # XXX: change once interrogate works on 3.12
- cache: pip
+ python-version-file: .python-version-default
+ - uses: hynek/setup-cached-uv@v2
+
+ - run: >
+ uvx --with tox-uv
+ tox run -e lint -- --show-diff-on-failure
+
+
+ build-package:
+ name: Build & verify package
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - uses: hynek/build-and-inspect-python-package@v2
+ id: baipp
+
+ outputs:
+ # Used to define the matrix for tests below. The value is based on
+ # packaging metadata (trove classifiers).
+ python-versions: ${{
steps.baipp.outputs.supported_python_classifiers_json_array }}
- - name: Install & run tox
- run: |
- python -Im pip install tox
- python -Im tox run -e lint -- --show-diff-on-failure
tests:
- name: Tests on ${{ matrix.python-version }}
+ name: Tests & Mypy API on ${{ matrix.python-version }}
runs-on: ubuntu-latest
+ needs: build-package
strategy:
matrix:
- python-version:
- - "3.8"
- - "3.9"
- - "3.10"
- - "3.11"
- - "3.12"
- - "pypy-3.8"
- - "pypy-3.9"
+ # Created by the build-and-inspect-python-package action above.
+ python-version: ${{
fromJson(needs.build-package.outputs.python-versions) }}
steps:
- - uses: actions/checkout@v4
+ - name: Download pre-built packages
+ uses: actions/download-artifact@v4
+ with:
+ name: Packages
+ path: dist
+ - run: |
+ tar xf dist/*.tar.gz --strip-components=1
+ rm -rf src
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- cache: pip
-
- - name: Prepare tox & run tests
- run: |
- V=${{ matrix.python-version }}
+ - uses: hynek/setup-cached-uv@v2
- if [[ "$V" = pypy-* ]]; then
- V=pypy3
- else
- V=py$(echo $V | tr -d .)
- fi
-
- python -Im pip install tox
- python -Im tox run -f "$V"
-
- - name: Run Mypy on API
- run: python -Im tox run -e mypy-api
+ - name: Run tests
+ run: >
+ uvx --with tox-uv
+ tox run
+ --installpkg dist/*.whl
+ -f py$(echo ${{ matrix.python-version }} | tr -d .)
- name: Upload coverage data
uses: actions/upload-artifact@v4
with:
name: coverage-data-${{ matrix.python-version }}
path: .coverage.*
+ include-hidden-files: true
if-no-files-found: ignore
+ - name: Check public API with Mypy
+ run: >
+ uvx --with tox-uv
+ tox run
+ --installpkg dist/*.whl
+ -e mypy-api
+
+
coverage:
- name: Combine & check coverage
+ name: Ensure 100% test coverage
needs: tests
runs-on: ubuntu-latest
@@ -85,7 +107,7 @@
- uses: actions/setup-python@v5
with:
python-version-file: .python-version-default
- cache: pip
+ - uses: hynek/setup-cached-uv@v2
- uses: actions/download-artifact@v4
with:
@@ -94,16 +116,16 @@
- name: Combine coverage & fail if it's <100%
run: |
- python -Im pip install coverage[toml]
+ uv tool install coverage[toml]
- python -Im coverage combine
- python -Im coverage html --skip-covered --skip-empty
+ coverage combine
+ coverage html --skip-covered --skip-empty
# Report and write to summary.
- python -Im coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
+ coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
# Report again and fail if under 100%.
- python -Im coverage report --fail-under=100
+ coverage report --fail-under=100
- name: Upload HTML report if check failed.
uses: actions/upload-artifact@v4
@@ -112,21 +134,28 @@
path: htmlcov
if: ${{ failure() }}
+
mypy-pkg:
- name: Type-check package
+ name: Mypy Codebase
runs-on: ubuntu-latest
+ needs: build-package
steps:
- - uses: actions/checkout@v4
+ - name: Download pre-built packages
+ uses: actions/download-artifact@v4
+ with:
+ name: Packages
+ path: dist
+ - run: tar xf dist/*.tar.gz --strip-components=1
- uses: actions/setup-python@v5
with:
python-version-file: .python-version-default
- cache: pip
+ - uses: hynek/setup-cached-uv@v2
+
+ - run: >
+ uvx --with tox-uv
+ tox run -e mypy-pkg
- - name: Install & run tox
- run: |
- python -Im pip install tox
- python -Im tox run -e mypy-pkg
install-dev:
strategy:
@@ -147,25 +176,35 @@
run: |
python -Im pip install -e .[dev]
python -Ic 'import service_identity;
print(service_identity.__version__)'
+ python -Ic 'import service_identity.pyopenssl'
+ python -Ic 'import service_identity.cryptography'
+
docs:
name: Build docs & run doctests
+ needs: build-package
runs-on: ubuntu-latest
+
steps:
- - uses: actions/checkout@v4
+ - name: Download pre-built packages
+ uses: actions/download-artifact@v4
+ with:
+ name: Packages
+ path: dist
+ - run: tar xf dist/*.tar.gz --strip-components=1
- uses: actions/setup-python@v5
with:
# Keep in sync with tox.ini/docs & .readthedocs.yaml
python-version: "3.12"
- cache: pip
+ - uses: hynek/setup-cached-uv@v2
+
+ - run: >
+ uvx --with tox-uv
+ tox run -e docs
- - name: Install & run tox
- run: |
- python -Im pip install tox
- python -Im tox run -e docs
- # Ensure everything required is passing for branch protection.
required-checks-pass:
+ name: Ensure everything required is passing for branch protection
if: always()
needs:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/service-identity-24.1.0/.github/workflows/pypi-package.yml
new/service-identity-24.2.0/.github/workflows/pypi-package.yml
--- old/service-identity-24.1.0/.github/workflows/pypi-package.yml
2024-01-14 08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/.github/workflows/pypi-package.yml
2024-10-26 09:10:38.000000000 +0200
@@ -5,13 +5,13 @@
push:
branches: [main]
tags: ["*"]
- pull_request:
release:
types:
- published
workflow_dispatch:
permissions:
+ attestations: write
contents: read
id-token: write
@@ -27,6 +27,8 @@
fetch-depth: 0
- uses: hynek/build-and-inspect-python-package@v2
+ with:
+ attest-build-provenance-github: 'true'
# Upload to Test PyPI on every commit on main.
release-test-pypi:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/.pre-commit-config.yaml
new/service-identity-24.2.0/.pre-commit-config.yaml
--- old/service-identity-24.1.0/.pre-commit-config.yaml 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/.pre-commit-config.yaml 2024-10-26
09:10:38.000000000 +0200
@@ -1,31 +1,26 @@
---
repos:
- - repo: https://github.com/psf/black
- rev: 23.12.1
- hooks:
- - id: black
-
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.1.13
+ rev: v0.7.1
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
+ - id: ruff-format
- repo: https://github.com/codespell-project/codespell
- rev: v2.2.6
+ rev: v2.3.0
hooks:
- id: codespell
args: [-L, fo]
- repo: https://github.com/econchick/interrogate
- rev: 1.5.0
+ rev: 1.7.0
hooks:
- id: interrogate
- language_version: python3.11
- args: [tests, -v]
+ args: [tests]
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.5.0
+ rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/.python-version-default
new/service-identity-24.2.0/.python-version-default
--- old/service-identity-24.1.0/.python-version-default 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/.python-version-default 2024-10-26
09:10:38.000000000 +0200
@@ -1 +1 @@
-3.12
+3.13
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/.readthedocs.yaml
new/service-identity-24.2.0/.readthedocs.yaml
--- old/service-identity-24.1.0/.readthedocs.yaml 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/.readthedocs.yaml 2024-10-26
09:10:38.000000000 +0200
@@ -2,10 +2,14 @@
version: 2
build:
- os: ubuntu-22.04
+ os: ubuntu-lts-latest
tools:
# Keep in-sync with tox.ini/docs and ci.yml/docs
python: "3.12"
+ jobs:
+ # Need the tags to calculate the version (sometimes).
+ post_checkout:
+ - git fetch --tags
python:
install:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/CHANGELOG.md
new/service-identity-24.2.0/CHANGELOG.md
--- old/service-identity-24.1.0/CHANGELOG.md 2024-01-14 08:05:19.000000000
+0100
+++ new/service-identity-24.2.0/CHANGELOG.md 2024-10-26 09:10:38.000000000
+0200
@@ -13,6 +13,21 @@
<!-- changelog follows -->
+## [24.2.0](https://github.com/pyca/service-identity/compare/24.1.0...24.2.0)
- 2024-10-26
+
+### Added
+
+- Python 3.13 is now officially supported.
+ [#74](https://github.com/pyca/service-identity/pull/74)
+
+
+### Changed
+
+- pyOpenSSL's identity extraction has been reimplemented using
*cryptography*'s primitives instead of deprecated pyOpenSSL APIs.
+ As a result, the oldest supported pyOpenSSL version is now 17.1.0.
+ [#70](https://github.com/pyca/service-identity/pull/70)
+
+
## [24.1.0](https://github.com/pyca/service-identity/compare/23.1.0...24.1.0)
- 2024-01-14
### Changed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/README.md
new/service-identity-24.2.0/README.md
--- old/service-identity-24.1.0/README.md 2024-01-14 08:05:19.000000000
+0100
+++ new/service-identity-24.2.0/README.md 2024-10-26 09:10:38.000000000
+0200
@@ -36,8 +36,7 @@
### *service-identity* for Enterprise
-Available as part of the Tidelift Subscription.
+Available as part of the [Tidelift
Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek).
The maintainers of *service-identity* and thousands of other packages are
working with Tidelift to deliver commercial support and maintenance for the
open-source packages you use to build your applications.
Save time, reduce risk, and improve code health, while paying the maintainers
of the exact packages you use.
-[Learn more.](https://tidelift.com/lifter/search/pypi/service-identity)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/docs/conf.py
new/service-identity-24.2.0/docs/conf.py
--- old/service-identity-24.1.0/docs/conf.py 2024-01-14 08:05:19.000000000
+0100
+++ new/service-identity-24.2.0/docs/conf.py 2024-10-26 09:10:38.000000000
+0200
@@ -1,16 +1,6 @@
from importlib import metadata
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-# sys.path.insert(0, os.path.abspath('.'))
-
-# -- General configuration ------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-# needs_sphinx = '1.0'
-
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
@@ -45,9 +35,6 @@
# The suffix of source filenames.
source_suffix = ".rst"
-# The encoding of source files.
-# source_encoding = 'utf-8-sig'
-
# The master toctree document.
master_doc = "index"
@@ -68,50 +55,16 @@
if "dev" in release:
release = version = "UNRELEASED"
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-# language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-# today = ''
-# Else, today_fmt is used as the format for a strftime call.
-# today_fmt = '%B %d, %Y'
-
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build"]
-# The reST default role (used for this markup: `text`) to use for all
-# documents.
-# default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-# add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-# add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-# show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-# pygments_style = "sphinx"
-
-# A list of ignored prefixes for module index sorting.
-# modindex_common_prefix = []
-
-# If true, keep warnings as "system message" paragraphs in the built documents.
-# keep_warnings = False
-
# -- Options for HTML output ----------------------------------------------
html_theme = "furo"
html_theme_options = {
- "top_of_page_button": None,
+ "top_of_page_buttons": [],
"light_css_variables": {
"font-stack": "Inter, sans-serif",
"font-stack--monospace": "BerkeleyMono, MonoLisa, ui-monospace, "
@@ -142,27 +95,6 @@
)
]
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-# latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-# latex_use_parts = False
-
-# If true, show page references after internal links.
-# latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-# latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-# latex_appendices = []
-
-# If false, no module index is generated.
-# latex_domain_indices = True
-
-
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
@@ -177,10 +109,6 @@
)
]
-# If true, show URL addresses after external links.
-# man_show_urls = False
-
-
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
@@ -198,18 +126,6 @@
)
]
-# Documents to append as an appendix to all manuals.
-# texinfo_appendices = []
-
-# If false, no module index is generated.
-# texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-# texinfo_show_urls = 'footnote'
-
-# If true, do not generate a @detailmenu in the "Top" node's menu.
-# texinfo_no_detailmenu = False
-
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/pyproject.toml
new/service-identity-24.2.0/pyproject.toml
--- old/service-identity-24.1.0/pyproject.toml 2024-01-14 08:05:19.000000000
+0100
+++ new/service-identity-24.2.0/pyproject.toml 2024-10-26 09:10:38.000000000
+0200
@@ -18,6 +18,7 @@
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
+ "Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Security :: Cryptography",
@@ -88,12 +89,8 @@
addopts = ["-ra", "--strict-markers", "--strict-config"]
xfail_strict = true
testpaths = "tests"
-filterwarnings = [
- "once::Warning",
- "ignore:::aiohttp[.*]",
- "ignore:::importlib[.*]",
- "ignore::DeprecationWarning:twisted.python.threadable",
-]
+filterwarnings = ["once::Warning"]
+norecursedirs = ["tests/typing"]
[tool.coverage.run]
@@ -132,55 +129,56 @@
whitelist-regex = ["test_.*"]
-[tool.black]
-line-length = 79
-
-
[tool.ruff]
src = ["src", "tests"]
-select = [
- "E", # pycodestyle
- "W", # pycodestyle
- "F", # Pyflakes
- "UP", # pyupgrade
- "N", # pep8-naming
- "YTT", # flake8-2020
- "S", # flake8-bandit
- "B", # flake8-bugbear
- "C4", # flake8-comprehensions
- "T10", # flake8-debugger
- "ISC", # flake8-implicit-str-concat
- "RET", # flake8-return
- "SIM", # flake8-simplify
- "DTZ", # flake8-datetimez
- "I", # isort
- "PGH", # pygrep-hooks
- "PLC", # Pylint
- "PIE", # flake8-pie
- "RUF", # ruff
-]
+line-length = 79
+
+[tool.ruff.lint]
+select = ["ALL"]
ignore = [
- "RUF001", # leave my smart characters alone
- "N801", # some artistic freedom when naming things after RFCs
- "N802", # ditto
+ "A001", # shadowing is fine
+ "ANN", # Mypy is better at this
+ "ARG001", # we don't control all args passed in
+ "ARG005", # we need stub lambdas
+ "COM", # ruff format takes care of our commas
+ "D", # We prefer our own docstring style.
+ "E501", # leave line-length enforcement to ruff format
+ "FIX", # Yes, we want XXX as a marker.
+ "INP001", # sometimes we want Python files outside of packages
+ "ISC001", # conflicts with ruff format
+ "N801", # some artistic freedom when naming things after RFCs
+ "N802", # ditto
+ "PLR2004", # numbers are sometimes fine
+ "RUF001", # leave my smart characters alone
+ "SLF001", # private members are accessed by friendly functions
+ "TCH", # TYPE_CHECKING blocks break autodocs
+ "TD", # we don't follow other people's todo style
]
-[tool.ruff.per-file-ignores]
+[tool.ruff.lint.per-file-ignores]
"tests/*" = [
+ "B018", # "useless" expressions can be useful in tests
+ "PLC1901", # empty strings are falsey, but are less specific in tests
+ "PT005", # we always add underscores and explicit name
+ "PT011", # broad is fine
"S101", # assert
"S301", # I know pickle is bad, but people use it.
- "SIM300", # Yoda rocks in tests
- "PLC1901", # empty strings are falsey, but are less specific in tests
- "B018", # "useless" expressions can be useful in tests
+ "SIM300", # Yoda rocks in asserts
+ "TRY301", # tests need to raise exceptions
+]
+"docs/pyopenssl_example.py" = [
+ "T201", # print is fine in the example
+ "T203", # pprint is fine in the example
]
-[tool.ruff.isort]
+[tool.ruff.lint.isort]
lines-between-types = 1
lines-after-imports = 2
[tool.mypy]
strict = true
+pretty = true
show_error_codes = true
enable_error_code = ["ignore-without-code"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/service-identity-24.1.0/src/service_identity/__init__.py
new/service-identity-24.2.0/src/service_identity/__init__.py
--- old/service-identity-24.1.0/src/service_identity/__init__.py
2024-01-14 08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/src/service_identity/__init__.py
2024-10-26 09:10:38.000000000 +0200
@@ -2,7 +2,6 @@
Verify service identities.
"""
-
from . import cryptography, hazmat, pyopenssl
from .exceptions import (
CertificateError,
@@ -30,34 +29,10 @@
def __getattr__(name: str) -> str:
- dunder_to_metadata = {
- "__version__": "version",
- "__description__": "summary",
- "__uri__": "",
- "__url__": "",
- "__email__": "",
- }
- if name not in dunder_to_metadata:
- raise AttributeError(f"module {__name__} has no attribute {name}")
-
- import warnings
-
- from importlib.metadata import metadata
-
- warnings.warn(
- f"Accessing service_identity.{name} is deprecated and will be "
- "removed in a future release. Use importlib.metadata directly "
- "to query packaging metadata.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- meta = metadata("service-identity")
-
- if name in ("__uri__", "__url__"):
- return meta["Project-URL"].split(" ", 1)[1]
+ if name != "__version__":
+ msg = f"module {__name__} has no attribute {name}"
+ raise AttributeError(msg)
- if name == "__email__":
- return meta["Author-email"].split("<", 1)[1].rstrip(">")
+ from importlib.metadata import version
- return meta[dunder_to_metadata[name]]
+ return version("service-identity")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/service-identity-24.1.0/src/service_identity/cryptography.py
new/service-identity-24.2.0/src/service_identity/cryptography.py
--- old/service-identity-24.1.0/src/service_identity/cryptography.py
2024-01-14 08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/src/service_identity/cryptography.py
2024-10-26 09:10:38.000000000 +0200
@@ -163,7 +163,8 @@
if isinstance(srv, IA5String):
ids.append(SRVPattern.from_bytes(srv.asOctets()))
else: # pragma: no cover
- raise CertificateError("Unexpected certificate content.")
+ msg = "Unexpected certificate content."
+ raise CertificateError(msg)
return ids
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/service-identity-24.1.0/src/service_identity/hazmat.py
new/service-identity-24.2.0/src/service_identity/hazmat.py
--- old/service-identity-24.1.0/src/service_identity/hazmat.py 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/src/service_identity/hazmat.py 2024-10-26
09:10:38.000000000 +0200
@@ -51,9 +51,8 @@
if a pattern of the respective type is present.
"""
if not cert_patterns:
- raise CertificateError(
- "Certificate does not contain any `subjectAltName`s."
- )
+ msg = "Certificate does not contain any `subjectAltName`s."
+ raise CertificateError(msg)
errors = []
matches = _find_matches(cert_patterns, obligatory_ids) + _find_matches(
@@ -63,7 +62,9 @@
matched_ids = [match.service_id for match in matches]
for i in obligatory_ids:
if i not in matched_ids:
- errors.append(i.error_on_mismatch(mismatched_id=i))
+ errors.append( # noqa: PERF401
+ i.error_on_mismatch(mismatched_id=i)
+ )
for i in optional_ids:
# If an optional ID is not matched by a certificate pattern *but* there
@@ -73,7 +74,9 @@
if i not in matched_ids and _contains_instance_of(
cert_patterns, i.pattern_class
):
- errors.append(i.error_on_mismatch(mismatched_id=i))
+ errors.append( # noqa: PERF401
+ i.error_on_mismatch(mismatched_id=i)
+ )
if errors:
raise VerificationError(errors=errors)
@@ -95,7 +98,10 @@
for sid in service_ids:
for cid in cert_patterns:
if sid.verify(cid):
- matches.append(ServiceMatch(cert_pattern=cid, service_id=sid))
+ matches.append( # noqa: PERF401
+ ServiceMatch(cert_pattern=cid, service_id=sid)
+ )
+
return matches
@@ -121,9 +127,10 @@
try:
int(pattern)
- return True
except ValueError:
pass
+ else:
+ return True
try:
ipaddress.ip_address(pattern.replace("*", "1"))
@@ -147,12 +154,14 @@
@classmethod
def from_bytes(cls, pattern: bytes) -> DNSPattern:
if not isinstance(pattern, bytes):
- raise TypeError("The DNS pattern must be a bytes string.")
+ msg = "The DNS pattern must be a bytes string."
+ raise TypeError(msg)
pattern = pattern.strip()
if pattern == b"" or _is_ip_address(pattern) or b"\0" in pattern:
- raise CertificateError(f"Invalid DNS pattern {pattern!r}.")
+ msg = f"Invalid DNS pattern {pattern!r}."
+ raise CertificateError(msg)
pattern = pattern.translate(_TRANS_TO_LOWER)
if b"*" in pattern:
@@ -175,9 +184,8 @@
try:
return cls(pattern=ipaddress.ip_address(bs))
except ValueError:
- raise CertificateError(
- f"Invalid IP address pattern {bs!r}."
- ) from None
+ msg = f"Invalid IP address pattern {bs!r}."
+ raise CertificateError(msg) from None
@attr.s(slots=True)
@@ -194,12 +202,14 @@
@classmethod
def from_bytes(cls, pattern: bytes) -> URIPattern:
if not isinstance(pattern, bytes):
- raise TypeError("The URI pattern must be a bytes string.")
+ msg = "The URI pattern must be a bytes string."
+ raise TypeError(msg)
pattern = pattern.strip().translate(_TRANS_TO_LOWER)
if b":" not in pattern or b"*" in pattern or _is_ip_address(pattern):
- raise CertificateError(f"Invalid URI pattern {pattern!r}.")
+ msg = f"Invalid URI pattern {pattern!r}."
+ raise CertificateError(msg)
protocol_pattern, hostname = pattern.split(b":")
@@ -223,7 +233,8 @@
@classmethod
def from_bytes(cls, pattern: bytes) -> SRVPattern:
if not isinstance(pattern, bytes):
- raise TypeError("The SRV pattern must be a bytes string.")
+ msg = "The SRV pattern must be a bytes string."
+ raise TypeError(msg)
pattern = pattern.strip().translate(_TRANS_TO_LOWER)
@@ -233,7 +244,8 @@
or b"*" in pattern
or _is_ip_address(pattern)
):
- raise CertificateError(f"Invalid SRV pattern {pattern!r}.")
+ msg = f"Invalid SRV pattern {pattern!r}."
+ raise CertificateError(msg)
name, hostname = pattern.split(b".", 1)
return cls(
@@ -253,15 +265,12 @@
@runtime_checkable
class ServiceID(Protocol):
@property
- def pattern_class(self) -> type[CertificatePattern]:
- ...
+ def pattern_class(self) -> type[CertificatePattern]: ...
@property
- def error_on_mismatch(self) -> type[Mismatch]:
- ...
+ def error_on_mismatch(self) -> type[Mismatch]: ...
- def verify(self, pattern: CertificatePattern) -> bool:
- ...
+ def verify(self, pattern: CertificatePattern) -> bool: ...
@attr.s(init=False, slots=True)
@@ -279,25 +288,27 @@
def __init__(self, hostname: str):
if not isinstance(hostname, str):
- raise TypeError("DNS-ID must be a text string.")
+ msg = "DNS-ID must be a text string."
+ raise TypeError(msg)
hostname = hostname.strip()
if not hostname or _is_ip_address(hostname):
- raise ValueError("Invalid DNS-ID.")
+ msg = "Invalid DNS-ID."
+ raise ValueError(msg)
if any(ord(c) > 127 for c in hostname):
if idna:
ascii_id = idna.encode(hostname)
else:
- raise ImportError(
- "idna library is required for non-ASCII IDs."
- )
+ msg = "idna library is required for non-ASCII IDs."
+ raise ImportError(msg)
else:
ascii_id = hostname.encode("ascii")
self.hostname = ascii_id.translate(_TRANS_TO_LOWER)
if self._RE_LEGAL_CHARS.match(self.hostname) is None:
- raise ValueError("Invalid DNS-ID.")
+ msg = "Invalid DNS-ID."
+ raise ValueError(msg)
def verify(self, pattern: CertificatePattern) -> bool:
"""
@@ -346,11 +357,13 @@
def __init__(self, uri: str):
if not isinstance(uri, str):
- raise TypeError("URI-ID must be a text string.")
+ msg = "URI-ID must be a text string."
+ raise TypeError(msg)
uri = uri.strip()
if ":" not in uri or _is_ip_address(uri):
- raise ValueError("Invalid URI-ID.")
+ msg = "Invalid URI-ID."
+ raise ValueError(msg)
prot, hostname = uri.split(":")
@@ -384,11 +397,13 @@
def __init__(self, srv: str):
if not isinstance(srv, str):
- raise TypeError("SRV-ID must be a text string.")
+ msg = "SRV-ID must be a text string."
+ raise TypeError(msg)
srv = srv.strip()
if "." not in srv or _is_ip_address(srv) or srv[0] != "_":
- raise ValueError("Invalid SRV-ID.")
+ msg = "Invalid SRV-ID."
+ raise ValueError(msg)
name, hostname = srv.split(".", 1)
@@ -420,7 +435,7 @@
if actual_head.startswith(b"xn--"):
return False
- return cert_head == b"*" or cert_head == actual_head
+ return cert_head in (b"*", actual_head)
return cert_pattern == actual_hostname
@@ -432,25 +447,19 @@
"""
cnt = cert_pattern.count(b"*")
if cnt > 1:
- raise CertificateError(
- f"Certificate's DNS-ID {cert_pattern!r} contains too many
wildcards."
- )
+ msg = f"Certificate's DNS-ID {cert_pattern!r} contains too many
wildcards."
+ raise CertificateError(msg)
parts = cert_pattern.split(b".")
if len(parts) < 3:
- raise CertificateError(
- f"Certificate's DNS-ID {cert_pattern!r} has too few host
components for "
- "wildcard usage."
- )
+ msg = f"Certificate's DNS-ID {cert_pattern!r} has too few host
components for wildcard usage."
+ raise CertificateError(msg)
# We assume there will always be only one wildcard allowed.
if b"*" not in parts[0]:
- raise CertificateError(
- "Certificate's DNS-ID {!r} has a wildcard outside the left-most "
- "part.".format(cert_pattern)
- )
+ msg = f"Certificate's DNS-ID {cert_pattern!r} has a wildcard outside
the left-most part."
+ raise CertificateError(msg)
if any(not len(p) for p in parts):
- raise CertificateError(
- f"Certificate's DNS-ID {cert_pattern!r} contains empty parts."
- )
+ msg = f"Certificate's DNS-ID {cert_pattern!r} contains empty parts."
+ raise CertificateError(msg)
# Ensure no locale magic interferes.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/service-identity-24.1.0/src/service_identity/pyopenssl.py
new/service-identity-24.2.0/src/service_identity/pyopenssl.py
--- old/service-identity-24.1.0/src/service_identity/pyopenssl.py
2024-01-14 08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/src/service_identity/pyopenssl.py
2024-10-26 09:10:38.000000000 +0200
@@ -9,20 +9,11 @@
from typing import Sequence
-from pyasn1.codec.der.decoder import decode
-from pyasn1.type.char import IA5String
-from pyasn1.type.univ import ObjectIdentifier
-from pyasn1_modules.rfc2459 import GeneralNames
-
-from .exceptions import CertificateError
+from .cryptography import extract_patterns as _cryptography_extract_patterns
from .hazmat import (
DNS_ID,
CertificatePattern,
- DNSPattern,
IPAddress_ID,
- IPAddressPattern,
- SRVPattern,
- URIPattern,
verify_service_identity,
)
@@ -105,9 +96,6 @@
)
-ID_ON_DNS_SRV = ObjectIdentifier("1.3.6.1.5.5.7.8.7") # id_on_dnsSRV
-
-
def extract_patterns(cert: X509) -> Sequence[CertificatePattern]:
"""
Extract all valid ID patterns from a certificate for service verification.
@@ -121,44 +109,7 @@
.. versionchanged:: 23.1.0
``commonName`` is not used as a fallback anymore.
"""
- ids: list[CertificatePattern] = []
- for i in range(cert.get_extension_count()):
- ext = cert.get_extension(i)
- if ext.get_short_name() == b"subjectAltName":
- names, _ = decode(ext.get_data(), asn1Spec=GeneralNames())
- for n in names:
- name_string = n.getName()
- if name_string == "dNSName":
- ids.append(
- DNSPattern.from_bytes(n.getComponent().asOctets())
- )
- elif name_string == "iPAddress":
- ids.append(
- IPAddressPattern.from_bytes(
- n.getComponent().asOctets()
- )
- )
- elif name_string == "uniformResourceIdentifier":
- ids.append(
- URIPattern.from_bytes(n.getComponent().asOctets())
- )
- elif name_string == "otherName":
- comp = n.getComponent()
- oid = comp.getComponentByPosition(0)
- if oid == ID_ON_DNS_SRV:
- srv, _ = decode(comp.getComponentByPosition(1))
- if isinstance(srv, IA5String):
- ids.append(SRVPattern.from_bytes(srv.asOctets()))
- else: # pragma: no cover
- raise CertificateError(
- "Unexpected certificate content."
- )
- else: # pragma: no cover
- pass
- else: # pragma: no cover
- pass
-
- return ids
+ return _cryptography_extract_patterns(cert.to_cryptography())
def extract_ids(cert: X509) -> Sequence[CertificatePattern]:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/service-identity-24.1.0/tests/constraints/oldest-pyopenssl.txt
new/service-identity-24.2.0/tests/constraints/oldest-pyopenssl.txt
--- old/service-identity-24.1.0/tests/constraints/oldest-pyopenssl.txt
2024-01-14 08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/tests/constraints/oldest-pyopenssl.txt
2024-10-26 09:10:38.000000000 +0200
@@ -1,3 +1,3 @@
attrs==19.1.0
cryptography<35
-pyOpenSSL==17.0.0
+pyOpenSSL==17.1.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/tests/test_hazmat.py
new/service-identity-24.2.0/tests/test_hazmat.py
--- old/service-identity-24.1.0/tests/test_hazmat.py 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/tests/test_hazmat.py 2024-10-26
09:10:38.000000000 +0200
@@ -699,11 +699,11 @@
"""
The __str__ and __repr__ methods return something helpful.
"""
- try:
+ with pytest.raises(VerificationError) as ei:
raise VerificationError(errors=["foo"])
- except VerificationError as e:
- assert repr(e) == str(e)
- assert str(e) != ""
+
+ assert repr(ei.value) == str(ei.value)
+ assert str(ei.value) != ""
@pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1))
@pytest.mark.parametrize(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/tests/test_packaging.py
new/service-identity-24.2.0/tests/test_packaging.py
--- old/service-identity-24.1.0/tests/test_packaging.py 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/tests/test_packaging.py 2024-10-26
09:10:38.000000000 +0200
@@ -10,38 +10,10 @@
"""
service_identity.__version__ returns the correct version.
"""
- with pytest.deprecated_call():
- assert (
- metadata.version("service-identity")
- == service_identity.__version__
- )
-
- def test_description(self):
- """
- service_identity.__description__ returns the correct description.
- """
- with pytest.deprecated_call():
- assert (
- "Service identity verification for pyOpenSSL & cryptography."
- == service_identity.__description__
- )
-
- @pytest.mark.parametrize("name", ["uri", "url"])
- def test_uri(self, name):
- """
- service_identity.__uri__ & __url__ return the correct project URL.
- """
- with pytest.deprecated_call():
- assert "https://service-identity.readthedocs.io/" == getattr(
- service_identity, f"__{name}__"
- )
-
- def test_email(self):
- """
- service_identity.__email__ returns Hynek's email address.
- """
- with pytest.deprecated_call():
- assert "[email protected]" == service_identity.__email__
+ assert (
+ metadata.version("service-identity")
+ == service_identity.__version__
+ )
def test_does_not_exist(self):
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/tests/typing/api.py
new/service-identity-24.2.0/tests/typing/api.py
--- old/service-identity-24.1.0/tests/typing/api.py 2024-01-14
08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/tests/typing/api.py 2024-10-26
09:10:38.000000000 +0200
@@ -20,9 +20,9 @@
backend = default_backend()
c_cert = load_pem_x509_certificate("foo.pem", backend)
-c_ids: Sequence[
- service_identity.hazmat.CertificatePattern
-] = service_identity.cryptography.extract_patterns(c_cert)
+c_ids: Sequence[service_identity.hazmat.CertificatePattern] = (
+ service_identity.cryptography.extract_patterns(c_cert)
+)
service_identity.cryptography.verify_certificate_hostname(
c_cert, "example.com"
)
@@ -36,8 +36,8 @@
p_cert = conn.get_peer_certificate()
assert p_cert
-p_ids: Sequence[
- service_identity.hazmat.CertificatePattern
-] = service_identity.pyopenssl.extract_patterns(p_cert)
+p_ids: Sequence[service_identity.hazmat.CertificatePattern] = (
+ service_identity.pyopenssl.extract_patterns(p_cert)
+)
service_identity.pyopenssl.verify_hostname(conn, "example.com")
service_identity.pyopenssl.verify_ip_address(conn, "127.0.0.1")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/service-identity-24.1.0/tox.ini
new/service-identity-24.2.0/tox.ini
--- old/service-identity-24.1.0/tox.ini 2024-01-14 08:05:19.000000000 +0100
+++ new/service-identity-24.2.0/tox.ini 2024-10-26 09:10:38.000000000 +0200
@@ -4,8 +4,7 @@
lint,
mypy-{api,pkg},
docs,
- pypy3{,-pyopenssl-latest-idna},
- py3{8,9,10,11,12}{,-pyopenssl}{,-oldest}{,-idna},
+ py3{8,9,10,11,12,13}{,-pyopenssl}{,-oldest}{,-idna},
coverage-report
@@ -40,7 +39,7 @@
[testenv:lint]
skip_install = true
-deps = pre-commit
+deps = pre-commit-uv
commands = pre-commit run --all-files {posargs}