fix: secure Python package baseline
This commit is contained in:
1 parent
3dce6c0b8d
commit
3e7786bb73
4 files changed
+92
-12
No files matched your search
@@ -8,7 +8,7 @@ Official Python SDK for the [Elydora](https://elydora.com) tamper-evident audit
|
|||||||
pip install elydora
|
pip install elydora
|
||||||
```
|
```
|
||||||
|
|
||||||
Requires Python 3.9+.
|
Requires Python 3.10+.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
"""Type definitions matching the Elydora backend API contract.
|
"""Type definitions matching the Elydora backend API contract.
|
||||||
|
|
||||||
All types use TypedDict for structural typing, compatible with Python 3.9+.
|
All types use TypedDict for structural typing, compatible with Python 3.10+.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
+10
-10
@@ -1,5 +1,5 @@
|
|||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools>=68.0", "wheel"]
|
requires = ["setuptools>=77.0.3", "wheel"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
@@ -7,24 +7,24 @@ name = "elydora"
|
|||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
description = "Python SDK for the Elydora tamper-evident audit platform"
|
description = "Python SDK for the Elydora tamper-evident audit platform"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = {text = "MIT"}
|
license = "MIT"
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.10"
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 5 - Production/Stable",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"License :: OSI Approved :: MIT License",
|
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.9",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python :: 3.13",
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Programming Language :: Python :: 3.14",
|
||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"requests>=2.28.0",
|
"requests>=2.33.0",
|
||||||
"aiohttp>=3.8.0",
|
"aiohttp>=3.14.1",
|
||||||
"cryptography>=41.0.0",
|
"urllib3>=2.7.0",
|
||||||
|
"cryptography>=48.0.1",
|
||||||
"tomlkit>=0.15.1,<1.0.0",
|
"tomlkit>=0.15.1,<1.0.0",
|
||||||
"typing_extensions>=4.0.0;python_version<'3.11'",
|
"typing_extensions>=4.0.0;python_version<'3.11'",
|
||||||
]
|
]
|
||||||
@@ -34,8 +34,8 @@ elydora = "elydora.cli:main"
|
|||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
dev = [
|
dev = [
|
||||||
"pytest>=7.0",
|
"pytest>=9.0.3",
|
||||||
"pytest-asyncio>=0.21",
|
"pytest-asyncio>=1.4.0",
|
||||||
"mypy>=1.0",
|
"mypy>=1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from packaging.requirements import Requirement
|
||||||
|
from packaging.version import Version
|
||||||
|
import tomlkit
|
||||||
|
|
||||||
|
|
||||||
|
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
def _pyproject() -> dict[str, object]:
|
||||||
|
return tomlkit.parse((PROJECT_ROOT / "pyproject.toml").read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def _project_metadata() -> dict[str, object]:
|
||||||
|
return _pyproject()["project"]
|
||||||
|
|
||||||
|
|
||||||
|
def _requirements(entries: object) -> dict[str, Requirement]:
|
||||||
|
assert isinstance(entries, list)
|
||||||
|
requirements = (Requirement(str(entry)) for entry in entries)
|
||||||
|
return {requirement.name: requirement for requirement in requirements}
|
||||||
|
|
||||||
|
|
||||||
|
def _assert_safe_floor(
|
||||||
|
requirement: Requirement,
|
||||||
|
vulnerable: str,
|
||||||
|
fixed: str,
|
||||||
|
) -> None:
|
||||||
|
assert Version(vulnerable) not in requirement.specifier
|
||||||
|
assert Version(fixed) in requirement.specifier
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_support_matches_maintained_runtime_line() -> None:
|
||||||
|
project = _project_metadata()
|
||||||
|
|
||||||
|
assert project["requires-python"] == ">=3.10"
|
||||||
|
assert "Programming Language :: Python :: 3.9" not in project["classifiers"]
|
||||||
|
assert "Programming Language :: Python :: 3.14" in project["classifiers"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_license_uses_current_packaging_metadata() -> None:
|
||||||
|
document = _pyproject()
|
||||||
|
project = document["project"]
|
||||||
|
assert isinstance(project, dict)
|
||||||
|
build_system = document["build-system"]
|
||||||
|
assert isinstance(build_system, dict)
|
||||||
|
build_requirements = _requirements(build_system["requires"])
|
||||||
|
|
||||||
|
assert project["license"] == "MIT"
|
||||||
|
assert all(
|
||||||
|
not str(classifier).startswith("License ::")
|
||||||
|
for classifier in project["classifiers"]
|
||||||
|
)
|
||||||
|
assert Version("77.0.3") in build_requirements["setuptools"].specifier
|
||||||
|
|
||||||
|
|
||||||
|
def test_dependency_floors_exclude_known_vulnerable_releases() -> None:
|
||||||
|
project = _project_metadata()
|
||||||
|
runtime = _requirements(project["dependencies"])
|
||||||
|
optional = project["optional-dependencies"]
|
||||||
|
assert isinstance(optional, dict)
|
||||||
|
development = _requirements(optional["dev"])
|
||||||
|
|
||||||
|
_assert_safe_floor(runtime["requests"], "2.32.5", "2.33.0")
|
||||||
|
_assert_safe_floor(runtime["aiohttp"], "3.13.5", "3.14.1")
|
||||||
|
_assert_safe_floor(runtime["urllib3"], "2.6.3", "2.7.0")
|
||||||
|
_assert_safe_floor(runtime["cryptography"], "41.0.0", "48.0.1")
|
||||||
|
_assert_safe_floor(development["pytest"], "8.4.2", "9.0.3")
|
||||||
|
|
||||||
|
|
||||||
|
def test_async_test_runner_supports_pytest_nine() -> None:
|
||||||
|
project = _project_metadata()
|
||||||
|
optional = project["optional-dependencies"]
|
||||||
|
assert isinstance(optional, dict)
|
||||||
|
development = _requirements(optional["dev"])
|
||||||
|
|
||||||
|
requirement = development["pytest-asyncio"]
|
||||||
|
assert Version("1.3.0") not in requirement.specifier
|
||||||
|
assert Version("1.4.0") in requirement.specifier
|
||||||
Reference in new issue
Block a user