From 8398d6c40cb77428bbc86416378b9c0ae297c480 Mon Sep 17 00:00:00 2001 From: TAHRI Ahmed R Date: Tue, 26 Sep 2023 14:03:54 +0200 Subject: [PATCH] :sparkle: Universal build fallback with certifi (#1) --- .github/workflows/CI.yml | 67 ++++++++++++++++++++++++++++++- CHANGELOG.md | 6 +++ Cargo.toml | 2 +- pyproject.fb.toml | 87 ++++++++++++++++++++++++++++++++++++++++ wassima/__init__.py | 48 +++++++++++++++++++++- wassima/__main__.py | 3 +- wassima/_version.py | 2 +- 7 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 pyproject.fb.toml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c750ddd..a030379 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -66,6 +66,13 @@ jobs: matrix: target: [x86_64, x86, aarch64, armv7, s390x, ppc64le] python_version: ['3.10', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9', 'pypy-3.10'] + manylinux: ['auto', 'musllinux_1_1'] + exclude: + - manylinux: musllinux_1_1 + target: ppc64le + - manylinux: musllinux_1_1 + target: s390x + steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 @@ -77,7 +84,7 @@ jobs: target: ${{ matrix.target }} args: --release --out dist --interpreter ${{ matrix.python_version }} sccache: 'true' - manylinux: auto + manylinux: ${{ matrix.manylinux }} - name: Upload wheels uses: actions/upload-artifact@v3 with: @@ -155,11 +162,67 @@ jobs: name: wheels path: dist + universal: + needs: + - test + - lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Install dependencies + run: python -m pip install build wheel + - name: Use fallback pyproject.toml + run: rm -f pyproject.toml && mv pyproject.fb.toml pyproject.toml + - name: Build fallback wheel + run: python -m build + - name: Upload sdist + uses: actions/upload-artifact@v3 + with: + name: wheels + path: dist/*.whl + + checksum: + name: Compute hashes + runs-on: ubuntu-latest + needs: [linux, windows, macos, sdist, universal] + if: "startsWith(github.ref, 'refs/tags/')" + outputs: + hashes: ${{ steps.compute.outputs.hashes }} + steps: + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - name: Download distributions + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: wheels + path: dist + - name: Collected dists + run: | + tree dist + - name: Generate hashes + id: compute # needs.checksum.outputs.hashes + working-directory: ./dist + run: echo "hashes=$(sha256sum * | base64 -w0)" >> $GITHUB_OUTPUT + + provenance: + needs: checksum + if: "startsWith(github.ref, 'refs/tags/')" + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0 + permissions: + actions: read + id-token: write + contents: write + with: + base64-subjects: ${{ needs.checksum.outputs.hashes }} + upload-assets: true + release: name: Release runs-on: ubuntu-latest if: "startsWith(github.ref, 'refs/tags/')" - needs: [linux, windows, macos, sdist] + needs: provenance steps: - uses: actions/download-artifact@v3 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c719d9..7b9b278 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to wassima will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## 1.0.1 (2023-09-26) + +### Added +- Expose `__version__`. +- Support for `certifi` fallback if you did not pick up a compatible wheel. Expose constant `RUSTLS_LOADED` as a witness. + ## 1.0.0 (2023-09-20) ### Added diff --git a/Cargo.toml b/Cargo.toml index 294e4c2..011b790 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wassima" -version = "1.0.0" +version = "1.0.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/pyproject.fb.toml b/pyproject.fb.toml new file mode 100644 index 0000000..e19f02f --- /dev/null +++ b/pyproject.fb.toml @@ -0,0 +1,87 @@ +[build-system] +requires = ["hatchling>=1.6.0,<2"] +build-backend = "hatchling.build" + +[project] +name = "wassima" +description = "Access your OS root certificates with the atmost ease" +readme = "README.md" +license-files = { paths = ["LICENSE"] } +license = "MIT" +keywords = ["truststore", "ssl", "tls", "root ca", "ca", "trust", "https", "certificate"] +authors = [ + {name = "Ahmed R. TAHRI", email="ahmed.tahri@cloudnursery.dev"}, +] +maintainers = [ + {name = "Ahmed R. TAHRI", email="ahmed.tahri@cloudnursery.dev"}, +] +requires-python = ">=3.7" +classifiers = [ + "Programming Language :: Rust", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3 :: Only", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Software Development :: Libraries", + "License :: OSI Approved :: MIT License", + "Development Status :: 5 - Production/Stable" +] +dynamic = ["version"] + +[tool.hatch.version] +path = "wassima/_version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/wassima", + "/tests", + "/requirements-dev.txt", + "/CHANGELOG.md", + "/README.md", + "/LICENSE", +] + +[tool.hatch.build.targets.wheel] +packages = [ + "wassima/", +] + +[project.urls] +"Changelog" = "https://github.com/jawah/wassima/blob/main/CHANGELOG.md" +"Documentation" = "https://wassima.readthedocs.io" +"Code" = "https://github.com/jawah/wassima" +"Issue tracker" = "https://github.com/jawah/wassima/issues" + +[tool.pytest.ini_options] +log_level = "DEBUG" + +[tool.isort] +profile = "black" +add_imports = "from __future__ import annotations" + +[tool.mypy] +mypy_path = "wassima" +check_untyped_defs = true +disallow_any_generics = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +no_implicit_optional = true +no_implicit_reexport = true +show_error_codes = true +strict_equality = true +warn_redundant_casts = true +warn_return_any = true +warn_unused_configs = true +warn_unused_ignores = true diff --git a/wassima/__init__.py b/wassima/__init__.py index 4cb6639..6ff1fd5 100644 --- a/wassima/__init__.py +++ b/wassima/__init__.py @@ -8,7 +8,49 @@ from functools import lru_cache from ssl import DER_cert_to_PEM_cert -from ._rustls import root_der_certificates +from ._version import VERSION, __version__ + +#: Determine if we could load correctly the non-native rust module. +RUSTLS_LOADED: bool + +try: + from ._rustls import root_der_certificates + + RUSTLS_LOADED = True +except ImportError: + RUSTLS_LOADED = False + from ssl import PEM_cert_to_DER_cert + + try: + import certifi # type: ignore + except ImportError: + certifi = None + + if certifi is None: + import platform + import warnings + + warnings.warn( + f"""Unable to access your system root CAs. Your particular interpreter and/or + operating system ({platform.python_implementation()}, {platform.uname()}, {platform.python_version()}) + is not be supported. While it is not ideal, you may circumvent that warning by having certifi + installed in your environment. Run `python -m pip install certifi`. + You may also open an issue at https://github.com/jawah/wassima/issues to get your platform compatible.""", + RuntimeWarning, + ) + + @lru_cache() + def root_der_certificates() -> list[bytes]: + if certifi is None: + return [] + + certs: list[bytes] = [] + + with open(certifi.where(), encoding="utf-8") as fp: + for pem_cert in fp.read().split("\n\n"): + certs.append(PEM_cert_to_DER_cert(pem_cert)) + + return certs @lru_cache() @@ -45,6 +87,7 @@ def create_default_ssl_context() -> ssl.SSLContext: ctx.load_verify_locations(cadata=generate_ca_bundle()) ctx.minimum_version = ssl.TLSVersion.TLSv1_2 ctx.set_ciphers("DEFAULT") + ctx.verify_mode = ssl.CERT_REQUIRED try: ctx.hostname_checks_common_name = False @@ -64,4 +107,7 @@ def create_default_ssl_context() -> ssl.SSLContext: "root_pem_certificates", "generate_ca_bundle", "create_default_ssl_context", + "__version__", + "VERSION", + "RUSTLS_LOADED", ) diff --git a/wassima/__main__.py b/wassima/__main__.py index 88b9012..6bfc644 100644 --- a/wassima/__main__.py +++ b/wassima/__main__.py @@ -1,6 +1,6 @@ from __future__ import annotations -from . import generate_ca_bundle +from . import RUSTLS_LOADED, generate_ca_bundle if __name__ == "__main__": bundle = generate_ca_bundle() @@ -13,6 +13,7 @@ print("uname: ", platform.uname()) print("python: ", platform.python_version_tuple()) print("implementation: ", platform.python_implementation()) + print("rustls loaded: ", RUSTLS_LOADED) exit(1) diff --git a/wassima/_version.py b/wassima/_version.py index c0d0ad5..bb53582 100644 --- a/wassima/_version.py +++ b/wassima/_version.py @@ -1,4 +1,4 @@ from __future__ import annotations -__version__ = "1.0.0" +__version__ = "1.0.1" VERSION = __version__.split(".")